├── .github └── workflows │ └── netcore.yml ├── .gitignore ├── LICENSE ├── README.md └── src ├── Genumerics.Benchmarks ├── Genumerics.Benchmarks.csproj └── Program.cs ├── Genumerics.Tests ├── EnumNumericOperations.cs ├── Genumerics.Tests.csproj ├── GenumericsDemo.cs ├── IntWrapper.cs └── NumberTests.cs ├── Genumerics.sln └── Genumerics ├── DefaultNumericOperations.cs ├── Genumerics.csproj ├── INumericOperations.cs ├── NullableAttributes.cs ├── NullableNumericOperations.cs ├── Number.cs ├── Number`1.cs ├── Number`2.cs ├── NumericOperationsProvider.cs ├── NumericOperationsWrapper.cs ├── Properties └── AssemblyInfo.cs └── genumerics.snk /.github/workflows/netcore.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | buildAndTest: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest, windows-latest, macOS-latest] 11 | 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Setup .NET Core 3.1 15 | uses: actions/setup-dotnet@v1 16 | with: 17 | dotnet-version: 3.1.x 18 | - name: Setup .NET 5 19 | uses: actions/setup-dotnet@v1 20 | with: 21 | dotnet-version: 5.0.x 22 | - name: Build and test with dotnet 23 | working-directory: src 24 | run: | 25 | dotnet build -c Release -f netcoreapp3.0 26 | dotnet test -f netcoreapp3.0 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tyler Brinkley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![GitHub last commit (master)](https://img.shields.io/github/last-commit/TylerBrinkley/Genumerics/master.svg?logo=github) 2 | [![NuGet Version](https://img.shields.io/nuget/v/Genumerics.svg?logo=nuget)](https://www.nuget.org/packages/Genumerics/) 3 | [![NuGet Downloads](https://img.shields.io/nuget/dt/Genumerics.svg?logo=nuget)](https://www.nuget.org/packages/Genumerics/) 4 | 5 | # Genumerics 6 | Genumerics is a high-performance .NET library for generic numeric operations. It is compatible with .NET Framework 4.5+ and .NET Standard 2.0+. 7 | 8 | ## The Problem 9 | You may have come across while working in .NET where you would like to perform numeric operations over a generic numeric type. Unfortunately .NET doesn't provide a way to do that natively. 10 | 11 | This library fills that gap by providing most standard numeric operations for the following built-in numeric types and their nullable equivalents with the ability to add support for other numeric types. 12 | 13 | `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, `decimal`, `nint`, `nuint`, and `BigInteger` 14 | 15 | ## Genumerics Demo 16 | Below is a demo of some basic uses of Genumerics in the form of unit tests. 17 | ```c# 18 | using Genumerics; 19 | using NUnit.Framework; 20 | 21 | public class GenumericsDemo 22 | { 23 | [TestCase(4, 5, 9)] 24 | [TestCase(2.25, 6.75, 9.0)] 25 | public void Add(T left, T right, T expected) 26 | { 27 | Assert.AreEqual(expected, Number.Add(left, right)); 28 | Assert.AreEqual(expected, AddWithOperator(left, right)); 29 | } 30 | 31 | private T AddWithOperator(Number left, Number right) => left + right; 32 | 33 | [TestCase(9, 6, true)] 34 | [TestCase(3.56, 4.07, false)] 35 | public void GreaterThan(T left, T right, bool expected) 36 | { 37 | Assert.AreEqual(expected, Number.GreaterThan(left, right)); 38 | Assert.AreEqual(expected, GreaterThanWithOperator(left, right)); 39 | } 40 | 41 | private bool GreaterThanWithOperator(Number left, Number right) => left > right; 42 | 43 | [TestCase(4, 4.0)] 44 | [TestCase(27.0, 27)] 45 | public void Convert(TFrom value, TTo expected) 46 | { 47 | Assert.AreEqual(expected, Number.Convert(value)); 48 | Assert.AreEqual(expected, Number.Create(value).To()); 49 | } 50 | 51 | [TestCase("98765", 98765)] 52 | [TestCase("12.3456789", 12.3456789)] 53 | public void Parse(string value, T expected) 54 | { 55 | Assert.AreEqual(expected, Number.Parse(value)); 56 | } 57 | 58 | [TestCase(123, null, "123")] 59 | [TestCase(255, "X", "FF")] 60 | public void ToString(T value, string? format, string expected) 61 | { 62 | Assert.AreEqual(expected, Number.ToString(value, format)); 63 | } 64 | 65 | [TestCase(sbyte.MaxValue)] 66 | [TestCase(float.MaxValue)] 67 | public void MaxValue(T expected) 68 | { 69 | Assert.AreEqual(expected, Number.MaxValue()); 70 | } 71 | } 72 | ``` 73 | 74 | ## Performance Comparison 75 | The summation algorithms below were benchmarked in .NET Core 3.0 and .NET 4.8 to determine the relative performance of the library compared with an `int` specific algorithm. As can be seen in the results, the performance is equivalent. 76 | 77 | ### Results 78 | | Method | Mean | Error | StdDev | Ratio | 79 | |----------- |-----------:|--------:|--------:|------:| 80 | | Sum | 531.0 ns | 1.40 ns | 1.31 ns | 1.00 | 81 | | SumNumber | 521.2 ns | 1.41 ns | 1.32 ns | 0.98 | 82 | | SumNumber2 | 531.7 ns | 0.81 ns | 0.76 ns | 1.00 | 83 | | SumAdd | 530.1 ns | 1.04 ns | 0.97 ns | 1.00 | 84 | | SumAdd2 | 532.2 ns | 1.60 ns | 1.33 ns | 1.00 | 85 | 86 | ### Code 87 | ```c# 88 | using System; 89 | using BenchmarkDotNet.Attributes; 90 | using BenchmarkDotNet.Jobs; 91 | using BenchmarkDotNet.Running; 92 | using Genumerics; 93 | 94 | public class Program 95 | { 96 | static void Main() => BenchmarkRunner.Run>(); 97 | } 98 | 99 | [SimpleJob(RuntimeMoniker.Net461), SimpleJob(RuntimeMoniker.NetCoreApp30), LegacyJitX86Job] 100 | public class SumBenchmarks 101 | where TNumericOperations : struct, INumericOperations 102 | { 103 | private int[] _intItems; 104 | private T[] _items; 105 | 106 | [Benchmark(Baseline = true)] 107 | public int Sum() 108 | { 109 | int sum = 0; 110 | foreach (int item in _intItems) 111 | { 112 | sum += item; 113 | } 114 | return sum; 115 | } 116 | 117 | [Benchmark] 118 | public T SumNumber() 119 | { 120 | Number sum = default; 121 | foreach (T item in _items) 122 | { 123 | sum += item; 124 | } 125 | return sum; 126 | } 127 | 128 | [Benchmark] 129 | public T SumNumber2() 130 | { 131 | Number sum = default; 132 | foreach (T item in _items) 133 | { 134 | sum += item; 135 | } 136 | return sum; 137 | } 138 | 139 | [Benchmark] 140 | public T SumAdd() 141 | { 142 | T sum = default; 143 | foreach (T item in _items) 144 | { 145 | sum = Number.Add(sum, item); 146 | } 147 | return sum; 148 | } 149 | 150 | [Benchmark] 151 | public T SumAdd2() 152 | { 153 | T sum = default; 154 | TNumericOperations operations = default; 155 | foreach (T item in _items) 156 | { 157 | sum = operations.Add(sum, item); 158 | } 159 | return sum; 160 | } 161 | 162 | [GlobalSetup] 163 | public void Setup() 164 | { 165 | _intItems = new int[1000]; 166 | _items = new T[1000]; 167 | Random rand = new Random(); 168 | for (int i = 0; i < 1000; ++i) 169 | { 170 | int value = rand.Next(10); 171 | _intItems[i] = value; 172 | _items[i] = Number.Create(value).To(); 173 | } 174 | } 175 | } 176 | ``` 177 | 178 | ## Interface 179 | 180 | See [fuget](https://www.fuget.org/packages/Genumerics/1.0.2/lib/netcoreapp3.0/Genumerics.dll/Genumerics/Number) for exploring the interface. 181 | -------------------------------------------------------------------------------- /src/Genumerics.Benchmarks/Genumerics.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Genumerics.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BenchmarkDotNet.Attributes; 3 | using BenchmarkDotNet.Jobs; 4 | using BenchmarkDotNet.Running; 5 | using Genumerics; 6 | 7 | public class Program 8 | { 9 | static void Main() => BenchmarkRunner.Run>(); 10 | } 11 | 12 | [SimpleJob(RuntimeMoniker.Net461), SimpleJob(RuntimeMoniker.NetCoreApp30), LegacyJitX86Job] 13 | public class SumBenchmarks 14 | where TNumericOperations : struct, INumericOperations 15 | { 16 | private int[] _intItems; 17 | private T[] _items; 18 | 19 | [Benchmark(Baseline = true)] 20 | public int Sum() 21 | { 22 | int sum = 0; 23 | foreach (int item in _intItems) 24 | { 25 | sum += item; 26 | } 27 | return sum; 28 | } 29 | 30 | [Benchmark] 31 | public T SumNumber() 32 | { 33 | Number sum = default; 34 | foreach (T item in _items) 35 | { 36 | sum += item; 37 | } 38 | return sum; 39 | } 40 | 41 | [Benchmark] 42 | public T SumNumber2() 43 | { 44 | Number sum = default; 45 | foreach (T item in _items) 46 | { 47 | sum += item; 48 | } 49 | return sum; 50 | } 51 | 52 | [Benchmark] 53 | public T SumAdd() 54 | { 55 | T sum = default; 56 | foreach (T item in _items) 57 | { 58 | sum = Number.Add(sum, item); 59 | } 60 | return sum; 61 | } 62 | 63 | [Benchmark] 64 | public T SumAdd2() 65 | { 66 | T sum = default; 67 | TNumericOperations operations = default; 68 | foreach (T item in _items) 69 | { 70 | sum = operations.Add(sum, item); 71 | } 72 | return sum; 73 | } 74 | 75 | [GlobalSetup] 76 | public void Setup() 77 | { 78 | _intItems = new int[1000]; 79 | _items = new T[1000]; 80 | Random rand = new Random(); 81 | for (int i = 0; i < 1000; ++i) 82 | { 83 | int value = rand.Next(10); 84 | _intItems[i] = value; 85 | _items[i] = Number.Create(value).To(); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/Genumerics.Tests/EnumNumericOperations.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Globalization; 28 | using System.Numerics; 29 | 30 | namespace Genumerics 31 | { 32 | /// 33 | /// Defines the numeric operations for enums. 34 | /// 35 | /// The enum type. 36 | /// The enum's underlying type. 37 | /// The underlying type's operations type. 38 | public struct EnumNumericOperations : INumericOperations 39 | where TEnum : struct, Enum 40 | where TUnderlying : struct 41 | where TUnderlyingOperations : struct, INumericOperations 42 | { 43 | #pragma warning disable IDE0052 // Remove unread private members, this will ensure a TypeInitializationException will occur when used improperly 44 | private static readonly bool s_initialized = Enum.GetUnderlyingType(typeof(TEnum)) == typeof(TUnderlying) ? true : throw new InvalidOperationException("TUnderlying must be TEnum's underlying type"); 45 | #pragma warning restore IDE0052 // Remove unread private members 46 | 47 | private static TEnum ToEnum(TUnderlying value) => (TEnum)Enum.ToObject(typeof(TEnum), value); 48 | 49 | private static TUnderlying ToUnderlying(TEnum value) => (TUnderlying)(object)value; 50 | 51 | /// 52 | public TEnum Zero => ToEnum(default(TUnderlyingOperations).Zero); 53 | 54 | /// 55 | public TEnum One => ToEnum(default(TUnderlyingOperations).One); 56 | 57 | /// 58 | public TEnum MinusOne => ToEnum(default(TUnderlyingOperations).MinusOne); 59 | 60 | /// 61 | public TEnum MaxValue => ToEnum(default(TUnderlyingOperations).MaxValue); 62 | 63 | /// 64 | public TEnum MinValue => ToEnum(default(TUnderlyingOperations).MinValue); 65 | 66 | /// 67 | public TypeCode TypeCode => default(TUnderlyingOperations).TypeCode; 68 | 69 | /// 70 | public TEnum Abs(TEnum value) => ToEnum(default(TUnderlyingOperations).Abs(ToUnderlying(value))); 71 | 72 | /// 73 | public TEnum Add(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).Add(ToUnderlying(left), ToUnderlying(right))); 74 | 75 | /// 76 | public TEnum BitwiseAnd(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).BitwiseAnd(ToUnderlying(left), ToUnderlying(right))); 77 | 78 | /// 79 | public TEnum Ceiling(TEnum value) => ToEnum(default(TUnderlyingOperations).Ceiling(ToUnderlying(value))); 80 | 81 | /// 82 | public TEnum Clamp(TEnum value, TEnum min, TEnum max) => ToEnum(default(TUnderlyingOperations).Clamp(ToUnderlying(value), ToUnderlying(min), ToUnderlying(max))); 83 | 84 | /// 85 | public int Compare(TEnum left, TEnum right) => default(TUnderlyingOperations).Compare(ToUnderlying(left), ToUnderlying(right)); 86 | 87 | /// 88 | public TEnum Convert(TFrom value) => ToEnum(default(TUnderlyingOperations).Convert(value)); 89 | 90 | /// 91 | public TEnum Divide(TEnum dividend, TEnum divisor) => ToEnum(default(TUnderlyingOperations).Divide(ToUnderlying(dividend), ToUnderlying(divisor))); 92 | 93 | /// 94 | public TEnum DivRem(TEnum dividend, TEnum divisor, out TEnum remainder) 95 | { 96 | var result = ToEnum(default(TUnderlyingOperations).DivRem(ToUnderlying(dividend), ToUnderlying(divisor), out var r)); 97 | remainder = ToEnum(r); 98 | return result; 99 | } 100 | 101 | /// 102 | public bool Equals(TEnum left, TEnum right) => default(TUnderlyingOperations).Equals(ToUnderlying(left), ToUnderlying(right)); 103 | 104 | /// 105 | public TEnum Floor(TEnum value) => ToEnum(default(TUnderlyingOperations).Floor(ToUnderlying(value))); 106 | 107 | /// 108 | public bool GreaterThan(TEnum left, TEnum right) => default(TUnderlyingOperations).GreaterThan(ToUnderlying(left), ToUnderlying(right)); 109 | 110 | /// 111 | public bool GreaterThanOrEqual(TEnum left, TEnum right) => default(TUnderlyingOperations).GreaterThanOrEqual(ToUnderlying(left), ToUnderlying(right)); 112 | 113 | /// 114 | public bool IsEven(TEnum value) => default(TUnderlyingOperations).IsEven(ToUnderlying(value)); 115 | 116 | /// 117 | public bool IsOdd(TEnum value) => default(TUnderlyingOperations).IsOdd(ToUnderlying(value)); 118 | 119 | /// 120 | public bool IsPowerOfTwo(TEnum value) => default(TUnderlyingOperations).IsPowerOfTwo(ToUnderlying(value)); 121 | 122 | /// 123 | public TEnum LeftShift(TEnum value, int shift) => ToEnum(default(TUnderlyingOperations).LeftShift(ToUnderlying(value), shift)); 124 | 125 | /// 126 | public bool LessThan(TEnum left, TEnum right) => default(TUnderlyingOperations).LessThan(ToUnderlying(left), ToUnderlying(right)); 127 | 128 | /// 129 | public bool LessThanOrEqual(TEnum left, TEnum right) => default(TUnderlyingOperations).LessThanOrEqual(ToUnderlying(left), ToUnderlying(right)); 130 | 131 | /// 132 | public TEnum Max(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).Max(ToUnderlying(left), ToUnderlying(right))); 133 | 134 | /// 135 | public TEnum Min(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).Min(ToUnderlying(left), ToUnderlying(right))); 136 | 137 | /// 138 | public TEnum Multiply(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).Multiply(ToUnderlying(left), ToUnderlying(right))); 139 | 140 | /// 141 | public TEnum Negate(TEnum value) => ToEnum(default(TUnderlyingOperations).Negate(ToUnderlying(value))); 142 | 143 | /// 144 | public TEnum OnesComplement(TEnum value) => ToEnum(default(TUnderlyingOperations).OnesComplement(ToUnderlying(value))); 145 | 146 | /// 147 | public bool NotEquals(TEnum left, TEnum right) => default(TUnderlyingOperations).NotEquals(ToUnderlying(left), ToUnderlying(right)); 148 | 149 | /// 150 | public TEnum BitwiseOr(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).BitwiseOr(ToUnderlying(left), ToUnderlying(right))); 151 | 152 | /// 153 | public TEnum Parse(string value, NumberStyles? style, IFormatProvider? provider) => style.HasValue ? 154 | ToEnum(default(TUnderlyingOperations).Parse(value, style, provider)) : 155 | #if GENERIC_ENUM_PARSE 156 | Enum.Parse(value); 157 | #else 158 | (TEnum)Enum.Parse(typeof(TEnum), value); 159 | #endif 160 | 161 | #if SPAN 162 | /// 163 | public TEnum Parse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider) => style.HasValue ? 164 | ToEnum(default(TUnderlyingOperations).Parse(value, style, provider)) : 165 | Enum.Parse(value.ToString()); 166 | #endif 167 | 168 | /// 169 | public TEnum Remainder(TEnum dividend, TEnum divisor) => ToEnum(default(TUnderlyingOperations).Remainder(ToUnderlying(dividend), ToUnderlying(divisor))); 170 | 171 | /// 172 | public TEnum RightShift(TEnum value, int shift) => ToEnum(default(TUnderlyingOperations).RightShift(ToUnderlying(value), shift)); 173 | 174 | /// 175 | public TEnum Round(TEnum value, int digits, MidpointRounding mode) => ToEnum(default(TUnderlyingOperations).Round(ToUnderlying(value), digits, mode)); 176 | 177 | /// 178 | public int Sign(TEnum value) => default(TUnderlyingOperations).Sign(ToUnderlying(value)); 179 | 180 | /// 181 | public TEnum Subtract(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).Subtract(ToUnderlying(left), ToUnderlying(right))); 182 | 183 | /// 184 | public BigInteger ToBigInteger(TEnum value) => default(TUnderlyingOperations).ToBigInteger(ToUnderlying(value)); 185 | 186 | /// 187 | public byte ToByte(TEnum value) => default(TUnderlyingOperations).ToByte(ToUnderlying(value)); 188 | 189 | /// 190 | public decimal ToDecimal(TEnum value) => default(TUnderlyingOperations).ToDecimal(ToUnderlying(value)); 191 | 192 | /// 193 | public double ToDouble(TEnum value) => default(TUnderlyingOperations).ToDouble(ToUnderlying(value)); 194 | 195 | /// 196 | public short ToInt16(TEnum value) => default(TUnderlyingOperations).ToInt16(ToUnderlying(value)); 197 | 198 | /// 199 | public int ToInt32(TEnum value) => default(TUnderlyingOperations).ToInt32(ToUnderlying(value)); 200 | 201 | /// 202 | public long ToInt64(TEnum value) => default(TUnderlyingOperations).ToInt64(ToUnderlying(value)); 203 | 204 | /// 205 | public sbyte ToSByte(TEnum value) => default(TUnderlyingOperations).ToSByte(ToUnderlying(value)); 206 | 207 | /// 208 | public float ToSingle(TEnum value) => default(TUnderlyingOperations).ToSingle(ToUnderlying(value)); 209 | 210 | /// 211 | public string ToString(TEnum value, string? format, IFormatProvider? provider) => value.ToString(format); 212 | 213 | /// 214 | public ushort ToUInt16(TEnum value) => default(TUnderlyingOperations).ToUInt16(ToUnderlying(value)); 215 | 216 | /// 217 | public uint ToUInt32(TEnum value) => default(TUnderlyingOperations).ToUInt32(ToUnderlying(value)); 218 | 219 | /// 220 | public ulong ToUInt64(TEnum value) => default(TUnderlyingOperations).ToUInt64(ToUnderlying(value)); 221 | 222 | /// 223 | public TEnum Truncate(TEnum value) => ToEnum(default(TUnderlyingOperations).Truncate(ToUnderlying(value))); 224 | 225 | #if SPAN 226 | /// 227 | public bool TryFormat(TEnum value, Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) 228 | { 229 | var str = value.ToString(format.ToString()); 230 | str.AsSpan().CopyTo(destination); 231 | charsWritten = str.Length; 232 | return true; 233 | } 234 | #endif 235 | 236 | /// 237 | public bool TryParse(string? value, NumberStyles? style, IFormatProvider? provider, out TEnum result) 238 | { 239 | if (style.HasValue) 240 | { 241 | var success = default(TUnderlyingOperations).TryParse(value, style, provider, out var r); 242 | result = ToEnum(r); 243 | return success; 244 | } 245 | return Enum.TryParse(value, out result); 246 | } 247 | 248 | #if SPAN 249 | /// 250 | public bool TryParse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider, out TEnum result) 251 | { 252 | if (style.HasValue) 253 | { 254 | var success = default(TUnderlyingOperations).TryParse(value, style, provider, out var r); 255 | result = ToEnum(r); 256 | return success; 257 | } 258 | return Enum.TryParse(value.ToString(), out result); 259 | } 260 | #endif 261 | 262 | /// 263 | public TEnum Xor(TEnum left, TEnum right) => ToEnum(default(TUnderlyingOperations).Xor(ToUnderlying(left), ToUnderlying(right))); 264 | 265 | /// 266 | public override bool Equals(object? obj) => obj is EnumNumericOperations; 267 | 268 | /// 269 | public override int GetHashCode() => nameof(EnumNumericOperations).GetHashCode(); 270 | 271 | #pragma warning disable IDE0060 // Remove unused parameter 272 | /// 273 | public static bool operator ==(EnumNumericOperations left, EnumNumericOperations right) => true; 274 | 275 | /// 276 | public static bool operator !=(EnumNumericOperations left, EnumNumericOperations right) => false; 277 | #pragma warning restore IDE0060 // Remove unused parameter 278 | } 279 | } -------------------------------------------------------------------------------- /src/Genumerics.Tests/Genumerics.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.0;netcoreapp2.1;netcoreapp2.0;net45 5 | false 6 | 9.0 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | GENERIC_ENUM_PARSE;SPAN 23 | 24 | 25 | 26 | GENERIC_ENUM_PARSE;SPAN 27 | 28 | 29 | 30 | GENERIC_ENUM_PARSE 31 | 32 | -------------------------------------------------------------------------------- /src/Genumerics.Tests/GenumericsDemo.cs: -------------------------------------------------------------------------------- 1 | using Genumerics; 2 | using NUnit.Framework; 3 | 4 | public class GenumericsDemo 5 | { 6 | [TestCase(4, 5, 9)] 7 | [TestCase(2.25, 6.75, 9.0)] 8 | public void Add(T left, T right, T expected) 9 | { 10 | Assert.AreEqual(expected, Number.Add(left, right)); 11 | Assert.AreEqual(expected, AddWithOperator(left, right)); 12 | } 13 | 14 | private T AddWithOperator(Number left, Number right) => left + right; 15 | 16 | [TestCase(9, 6, true)] 17 | [TestCase(3.56, 4.07, false)] 18 | public void GreaterThan(T left, T right, bool expected) 19 | { 20 | Assert.AreEqual(expected, Number.GreaterThan(left, right)); 21 | Assert.AreEqual(expected, GreaterThanWithOperator(left, right)); 22 | } 23 | 24 | private bool GreaterThanWithOperator(Number left, Number right) => left > right; 25 | 26 | [TestCase(4, 4.0)] 27 | [TestCase(27.0, 27)] 28 | public void Convert(TFrom value, TTo expected) 29 | { 30 | Assert.AreEqual(expected, Number.Convert(value)); 31 | Assert.AreEqual(expected, Number.Create(value).To()); 32 | } 33 | 34 | [TestCase("98765", 98765)] 35 | [TestCase("12.3456789", 12.3456789)] 36 | public void Parse(string value, T expected) 37 | { 38 | Assert.AreEqual(expected, Number.Parse(value)); 39 | } 40 | 41 | [TestCase(123, null, "123")] 42 | [TestCase(255, "X", "FF")] 43 | public void ToString(T value, string format, string expected) 44 | { 45 | Assert.AreEqual(expected, Number.ToString(value, format)); 46 | } 47 | 48 | [TestCase(sbyte.MaxValue)] 49 | [TestCase(float.MaxValue)] 50 | public void MaxValue(T expected) 51 | { 52 | Assert.AreEqual(expected, Number.MaxValue()); 53 | } 54 | } -------------------------------------------------------------------------------- /src/Genumerics.Tests/IntWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Numerics; 4 | 5 | namespace Genumerics.Tests 6 | { 7 | public struct IntWrapper 8 | { 9 | public int Value { get; } 10 | 11 | public IntWrapper(int value) 12 | { 13 | Value = value; 14 | } 15 | 16 | public static implicit operator IntWrapper(int value) => new(value); 17 | 18 | public static implicit operator int(IntWrapper value) => value.Value; 19 | } 20 | 21 | public struct IntWrapperOperations : INumericOperations 22 | { 23 | public IntWrapper Zero => Number.GetOperations()!.Zero; 24 | 25 | public IntWrapper One => Number.GetOperations()!.One; 26 | 27 | public IntWrapper MinusOne => Number.GetOperations()!.MinusOne; 28 | 29 | public IntWrapper MaxValue => Number.GetOperations()!.MaxValue; 30 | 31 | public IntWrapper MinValue => Number.GetOperations()!.MinValue; 32 | 33 | public TypeCode TypeCode => Number.GetOperations()!.TypeCode; 34 | 35 | public IntWrapper Abs(IntWrapper value) => Number.GetOperations()!.Abs(value); 36 | public IntWrapper Add(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Add(left, right); 37 | public IntWrapper BitwiseAnd(IntWrapper left, IntWrapper right) => Number.GetOperations()!.BitwiseAnd(left, right); 38 | public IntWrapper Ceiling(IntWrapper value) => Number.GetOperations()!.Ceiling(value); 39 | public IntWrapper Clamp(IntWrapper value, IntWrapper min, IntWrapper max) => Number.GetOperations()!.Clamp(value, min, max); 40 | public int Compare(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Compare(left, right); 41 | public IntWrapper Convert(TFrom value) => Number.GetOperations()!.Convert(value); 42 | public IntWrapper Divide(IntWrapper dividend, IntWrapper divisor) => Number.GetOperations()!.Divide(dividend, divisor); 43 | public IntWrapper DivRem(IntWrapper dividend, IntWrapper divisor, out IntWrapper remainder) 44 | { 45 | var result = Number.GetOperations()!.DivRem(dividend, divisor, out var intRemainder); 46 | remainder = intRemainder; 47 | return result; 48 | } 49 | public bool Equals(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Equals(left, right); 50 | public IntWrapper Floor(IntWrapper value) => Number.GetOperations()!.Floor(value); 51 | public bool GreaterThan(IntWrapper left, IntWrapper right) => Number.GetOperations()!.GreaterThan(left, right); 52 | public bool GreaterThanOrEqual(IntWrapper left, IntWrapper right) => Number.GetOperations()!.GreaterThanOrEqual(left, right); 53 | public bool IsEven(IntWrapper value) => Number.GetOperations()!.IsEven(value); 54 | public bool IsOdd(IntWrapper value) => Number.GetOperations()!.IsOdd(value); 55 | public bool IsPowerOfTwo(IntWrapper value) => Number.GetOperations()!.IsPowerOfTwo(value); 56 | public IntWrapper LeftShift(IntWrapper value, int shift) => Number.GetOperations()!.LeftShift(value, shift); 57 | public bool LessThan(IntWrapper left, IntWrapper right) => Number.GetOperations()!.LessThan(left, right); 58 | public bool LessThanOrEqual(IntWrapper left, IntWrapper right) => Number.GetOperations()!.LessThanOrEqual(left, right); 59 | public IntWrapper Max(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Max(left, right); 60 | public IntWrapper Min(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Min(left, right); 61 | public IntWrapper Multiply(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Multiply(left, right); 62 | public IntWrapper Negate(IntWrapper value) => Number.GetOperations()!.Negate(value); 63 | public IntWrapper OnesComplement(IntWrapper value) => Number.GetOperations()!.OnesComplement(value); 64 | public bool NotEquals(IntWrapper left, IntWrapper right) => Number.GetOperations()!.NotEquals(left, right); 65 | public IntWrapper BitwiseOr(IntWrapper left, IntWrapper right) => Number.GetOperations()!.BitwiseOr(left, right); 66 | public IntWrapper Parse(string value, NumberStyles? style, IFormatProvider? provider) => Number.GetOperations()!.Parse(value, style, provider); 67 | #if SPAN 68 | public IntWrapper Parse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider) => Number.GetOperations()!.Parse(value, style, provider); 69 | #endif 70 | public IntWrapper Remainder(IntWrapper dividend, IntWrapper divisor) => Number.GetOperations()!.Remainder(dividend, divisor); 71 | public IntWrapper RightShift(IntWrapper value, int shift) => Number.GetOperations()!.RightShift(value, shift); 72 | public IntWrapper Round(IntWrapper value, int digits, MidpointRounding mode) => Number.GetOperations()!.Round(value, digits, mode); 73 | public int Sign(IntWrapper value) => Number.GetOperations()!.Sign(value); 74 | public IntWrapper Subtract(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Subtract(left, right); 75 | public BigInteger ToBigInteger(IntWrapper value) => Number.GetOperations()!.ToBigInteger(value); 76 | public byte ToByte(IntWrapper value) => Number.GetOperations()!.ToByte(value); 77 | public decimal ToDecimal(IntWrapper value) => Number.GetOperations()!.ToDecimal(value); 78 | public double ToDouble(IntWrapper value) => Number.GetOperations()!.ToDouble(value); 79 | public short ToInt16(IntWrapper value) => Number.GetOperations()!.ToInt16(value); 80 | public int ToInt32(IntWrapper value) => Number.GetOperations()!.ToInt32(value); 81 | public long ToInt64(IntWrapper value) => Number.GetOperations()!.ToInt64(value); 82 | public sbyte ToSByte(IntWrapper value) => Number.GetOperations()!.ToSByte(value); 83 | public float ToSingle(IntWrapper value) => Number.GetOperations()!.ToSingle(value); 84 | public string ToString(IntWrapper value, string? format, IFormatProvider? provider) => Number.GetOperations()!.ToString(value, format, provider); 85 | public ushort ToUInt16(IntWrapper value) => Number.GetOperations()!.ToUInt16(value); 86 | public uint ToUInt32(IntWrapper value) => Number.GetOperations()!.ToUInt32(value); 87 | public ulong ToUInt64(IntWrapper value) => Number.GetOperations()!.ToUInt64(value); 88 | public IntWrapper Truncate(IntWrapper value) => Number.GetOperations()!.Truncate(value); 89 | #if SPAN 90 | public bool TryFormat(IntWrapper value, Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) => Number.GetOperations()!.TryFormat(value, destination, out charsWritten, format, provider); 91 | #endif 92 | public bool TryParse(string? value, NumberStyles? style, IFormatProvider? provider, out IntWrapper result) 93 | { 94 | var success = Number.GetOperations()!.TryParse(value, style, provider, out var intResult); 95 | result = intResult; 96 | return success; 97 | } 98 | #if SPAN 99 | public bool TryParse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider, out IntWrapper result) 100 | { 101 | var success = Number.GetOperations()!.TryParse(value, style, provider, out var intResult); 102 | result = intResult; 103 | return success; 104 | } 105 | #endif 106 | public IntWrapper Xor(IntWrapper left, IntWrapper right) => Number.GetOperations()!.Xor(left, right); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Genumerics.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29102.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Genumerics", "Genumerics\Genumerics.csproj", "{B87A3B68-DF70-466E-8D04-50DC27BF9644}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Genumerics.Tests", "Genumerics.Tests\Genumerics.Tests.csproj", "{91E84D20-A0CA-4E7B-8990-0634EC19347E}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4FBA507-CD1E-40A3-BCBC-4AF9F0D2EAE1}" 11 | ProjectSection(SolutionItems) = preProject 12 | ..\.gitignore = ..\.gitignore 13 | ..\LICENSE = ..\LICENSE 14 | ..\.github\workflows\netcore.yml = ..\.github\workflows\netcore.yml 15 | ..\README.md = ..\README.md 16 | EndProjectSection 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Genumerics.Benchmarks", "Genumerics.Benchmarks\Genumerics.Benchmarks.csproj", "{E1C4069A-C4E2-423B-BD30-E9B39315B593}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {B87A3B68-DF70-466E-8D04-50DC27BF9644}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {B87A3B68-DF70-466E-8D04-50DC27BF9644}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {B87A3B68-DF70-466E-8D04-50DC27BF9644}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {B87A3B68-DF70-466E-8D04-50DC27BF9644}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {91E84D20-A0CA-4E7B-8990-0634EC19347E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {91E84D20-A0CA-4E7B-8990-0634EC19347E}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {91E84D20-A0CA-4E7B-8990-0634EC19347E}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {91E84D20-A0CA-4E7B-8990-0634EC19347E}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {E1C4069A-C4E2-423B-BD30-E9B39315B593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {E1C4069A-C4E2-423B-BD30-E9B39315B593}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {E1C4069A-C4E2-423B-BD30-E9B39315B593}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {E1C4069A-C4E2-423B-BD30-E9B39315B593}.Release|Any CPU.Build.0 = Release|Any CPU 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {04C2CB3C-58A4-4B41-9837-ABFA67135BEC} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /src/Genumerics/Genumerics.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp3.0;netcoreapp2.1;netcoreapp2.0;netstandard2.1;netstandard2.0;net45 4 | 1.0.0.0 5 | 1.0.3 6 | 1.0.3 7 | 8 | True 9 | Tyler Brinkley 10 | Genumerics is a library that provides generic numeric operations 11 | Copyright © Tyler Brinkley 2019 12 | Genumerics is a library that provides generic numeric operations 13 | en-US 14 | Genumerics 15 | generic numerics number math 16 | https://github.com/TylerBrinkley/Genumerics 17 | 18 | True 19 | Genumerics 20 | Genumerics 21 | True 22 | MIT 23 | https://github.com/TylerBrinkley/Genumerics 24 | git 25 | true 26 | genumerics.snk 27 | enable 28 | 9.0 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Genumerics .NET Core 3.0 37 | MATHF;CLAMP;SPAN;NULLABLE_ATTRIBUTES 38 | 39 | 40 | 41 | Genumerics .NET Core 2.1 42 | MATHF;CLAMP;SPAN 43 | 44 | 45 | 46 | Genumerics .NET Core 2.0 47 | MATHF;CLAMP 48 | 49 | 50 | 51 | Genumerics .NET Standard 2.1 52 | MATHF;CLAMP;SPAN;NULLABLE_ATTRIBUTES 53 | 54 | 55 | 56 | Genumerics .NET Standard 2.0 57 | 58 | 59 | 60 | 61 | Genumerics .NET 4.5 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/Genumerics/INumericOperations.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Diagnostics.CodeAnalysis; 28 | using System.Globalization; 29 | using System.Numerics; 30 | 31 | namespace Genumerics 32 | { 33 | /// 34 | /// Provides the required numeric operations for the numeric type . 35 | /// 36 | /// The numeric type. 37 | [CLSCompliant(false)] 38 | public interface INumericOperations 39 | { 40 | /// 41 | /// Gets a value that represents the number zero (0). 42 | /// 43 | T Zero { get; } 44 | 45 | /// 46 | /// Gets a value that represents the number one (1). 47 | /// 48 | T One { get; } 49 | 50 | /// 51 | /// Gets a value that represents the number negative one (-1). 52 | /// 53 | T MinusOne { get; } 54 | 55 | /// 56 | /// Gets the largest possible value of . 57 | /// 58 | T MaxValue { get; } 59 | 60 | /// 61 | /// Gets the smallest possible value of . 62 | /// 63 | T MinValue { get; } 64 | 65 | /// 66 | /// Returns the for . 67 | /// 68 | TypeCode TypeCode { get; } 69 | 70 | /// 71 | /// Returns a value that indicates whether the values of the two objects are equal. 72 | /// 73 | /// The first value to compare. 74 | /// The second value to compare. 75 | /// true if the and parameters have the same value; otherwise, false. 76 | bool Equals(T left, T right); 77 | 78 | /// 79 | /// Returns a value that indicates whether the two objects have different values. 80 | /// 81 | /// The first value to compare. 82 | /// The second value to compare. 83 | /// true if and are not equal; otherwise, false. 84 | bool NotEquals(T left, T right); 85 | 86 | /// 87 | /// Returns a value that indicates whether a value is less than another value. 88 | /// 89 | /// The first value to compare. 90 | /// The second value to compare. 91 | /// true if is less than ; otherwise, false. 92 | bool LessThan(T left, T right); 93 | 94 | /// 95 | /// Returns a value that indicates whether a value is less than or equal to another value. 96 | /// 97 | /// The first value to compare. 98 | /// The second value to compare. 99 | /// true if is less than or equal to ; otherwise, false. 100 | bool LessThanOrEqual(T left, T right); 101 | 102 | /// 103 | /// Returns a value that indicates whether a value is greater than another value. 104 | /// 105 | /// The first value to compare. 106 | /// The second value to compare. 107 | /// true if is greater than ; otherwise, false. 108 | bool GreaterThan(T left, T right); 109 | 110 | /// 111 | /// Returns a value that indicates whether a value is greater than or equal to another value. 112 | /// 113 | /// The first value to compare. 114 | /// The second value to compare. 115 | /// true if is greater than ; otherwise, false. 116 | bool GreaterThanOrEqual(T left, T right); 117 | 118 | /// 119 | /// Adds two values and returns the result. 120 | /// 121 | /// The first value to add. 122 | /// The second value to add. 123 | /// The sum of and . 124 | T Add(T left, T right); 125 | 126 | /// 127 | /// Subtracts one value from another and returns the result. 128 | /// 129 | /// The value to subtract from (the minuend). 130 | /// The value to subtract (the subtrahend). 131 | /// The result of subtracting from . 132 | T Subtract(T left, T right); 133 | 134 | /// 135 | /// Returns the product of two values. 136 | /// 137 | /// The first number to multiply. 138 | /// The second number to multiply. 139 | /// The product of the and parameters. 140 | T Multiply(T left, T right); 141 | 142 | /// 143 | /// Divides one value by another and returns the result. 144 | /// 145 | /// The value to be divided. 146 | /// The value to divide by. 147 | /// The quotient of the division. 148 | T Divide(T dividend, T divisor); 149 | 150 | /// 151 | /// Performs division on two values and returns the remainder. 152 | /// 153 | /// The value to be divided. 154 | /// The value to divide by. 155 | /// The remainder after dividing by . 156 | T Remainder(T dividend, T divisor); 157 | 158 | /// 159 | /// Calculates the quotient of two values and also returns the remainder in an output parameter. 160 | /// 161 | /// The dividend. 162 | /// The divisor. 163 | /// The remainder. 164 | /// The quotient of the specified numbers. 165 | T DivRem(T dividend, T divisor, out T remainder); 166 | 167 | /// 168 | /// Negates a specified value. 169 | /// 170 | /// The value to negate. 171 | /// The result of the parameter multiplied by negative one (-1). 172 | T Negate(T value); 173 | 174 | /// 175 | /// Performs a bitwise And operation on two values. 176 | /// 177 | /// The first value. 178 | /// The second value. 179 | /// The result of the bitwise And operation. 180 | T BitwiseAnd(T left, T right); 181 | 182 | /// 183 | /// Performs a bitwise Or operation on two values. 184 | /// 185 | /// The first value. 186 | /// The second value. 187 | /// The result of the bitwise Or operation. 188 | T BitwiseOr(T left, T right); 189 | 190 | /// 191 | /// Performs a bitwise exclusive Or operation on two values. 192 | /// 193 | /// The first value. 194 | /// The second value. 195 | /// The result of the bitwise exclusive Or operation. 196 | T Xor(T left, T right); 197 | 198 | /// 199 | /// Returns the bitwise one's complement of a value. 200 | /// 201 | /// An integer value. 202 | /// The bitwise one's complement of . 203 | T OnesComplement(T value); 204 | 205 | /// 206 | /// Shifts a value a specified number of bits to the left. 207 | /// 208 | /// The value whose bits are to be shifted. 209 | /// The number of bits to shift value to the left. 210 | /// A value that has been shifted to the left by the specified number of bits. 211 | T LeftShift(T value, int shift); 212 | 213 | /// 214 | /// Shifts a value a specified number of bits to the right. 215 | /// 216 | /// The value whose bits are to be shifted. 217 | /// The number of bits to shift value to the right. 218 | /// A value that has been shifted to the right by the specified number of bits. 219 | T RightShift(T value, int shift); 220 | 221 | /// 222 | /// Converts the string representation of a number in a specified and culture-specific format to its equivalent. 223 | /// 224 | /// A string that contains a number to convert. 225 | /// A bitwise combination of the enumeration values that specify the permitted format of . 226 | /// An object that provides culture-specific formatting information about . 227 | /// A value that is equivalent to the number specified in the parameter. 228 | T Parse(string value, NumberStyles? style, IFormatProvider? provider); 229 | 230 | /// 231 | /// Tries to convert the string representation of a number in a specified and 232 | /// culture-specific format to its equivalent, and returns 233 | /// a value that indicates whether the conversion succeeded. 234 | /// 235 | /// The string representation of a number. The string is interpreted using the style specified by . 236 | /// A bitwise combination of enumeration values that indicates the style elements that can be present in . 237 | /// An object that supplies culture-specific formatting information about . 238 | /// When this method returns, contains the equivalent 239 | /// to the number that is contained in , or zero (0) 240 | /// if the conversion failed. The conversion fails if the value parameter is null 241 | /// or is not in a format that is compliant with . This parameter is passed 242 | /// uninitialized. 243 | /// true if the value parameter was converted successfully; otherwise, false. 244 | bool TryParse(string? value, NumberStyles? style, IFormatProvider? provider, out T result); 245 | 246 | #if SPAN 247 | /// 248 | /// Converts the string representation of a number in a specified and culture-specific format to its equivalent. 249 | /// 250 | /// A string that contains a number to convert. 251 | /// A bitwise combination of the enumeration values that specify the permitted format of . 252 | /// An object that provides culture-specific formatting information about . 253 | /// A value that is equivalent to the number specified in the parameter. 254 | T Parse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider); 255 | 256 | /// 257 | /// Tries to convert the string representation of a number in a specified and 258 | /// culture-specific format to its equivalent, and returns 259 | /// a value that indicates whether the conversion succeeded. 260 | /// 261 | /// The string representation of a number. The string is interpreted using the style specified by . 262 | /// A bitwise combination of enumeration values that indicates the style elements that can be present in . 263 | /// An object that supplies culture-specific formatting information about . 264 | /// When this method returns, contains the equivalent 265 | /// to the number that is contained in , or zero (0) 266 | /// if the conversion failed. The conversion fails if the value parameter is null 267 | /// or is not in a format that is compliant with . This parameter is passed 268 | /// uninitialized. 269 | /// true if the value parameter was converted successfully; otherwise, false. 270 | bool TryParse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider, out T result); 271 | 272 | /// 273 | /// Tries to convert the specified numeric value to its equivalent string representation into the destination by using the specified format and culture-specific format information. 274 | /// 275 | /// A number. 276 | /// The to write the string representation to. 277 | /// The number of characters written to . 278 | /// A standard or custom numeric format string. 279 | /// An object that supplies culture-specific formatting information. 280 | /// true if the value's string representation was successfully written to ; otherwise, false. 281 | bool TryFormat(T value, Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null); 282 | #endif 283 | 284 | /// 285 | /// Converts the specified value to its equivalent. 286 | /// 287 | /// The numeric type to convert from. 288 | /// The value to convert. 289 | /// A value that is equivalent to the number specified in the parameter. 290 | T Convert(TFrom value); 291 | 292 | /// 293 | /// Rounds a value to a specified number of fractional digits. A parameter specifies how to round the value if it is midway between two numbers. 294 | /// 295 | /// A number to be rounded. 296 | /// The number of fractional digits in the return value. 297 | /// Specification for how to round value if it is midway between two other numbers. 298 | /// The number nearest to that has a number of fractional digits equal to . 299 | /// If has fewer fractional digits than , is returned unchanged. 300 | T Round(T value, int digits, MidpointRounding mode); 301 | 302 | /// 303 | /// Returns the largest integer less than or equal to the specified number. 304 | /// 305 | /// A number. 306 | /// The largest integer less than or equal to . 307 | T Floor(T value); 308 | 309 | /// 310 | /// Returns the smallest integral value that is greater than or equal to the specified number. 311 | /// 312 | /// A number. 313 | /// The smallest integral value that is greater than or equal to . 314 | T Ceiling(T value); 315 | 316 | /// 317 | /// Calculates the integral part of a specified number. 318 | /// 319 | /// A number to truncate. 320 | /// The integral part of ; that is, the number that remains after any fractional digits have been discarded. 321 | T Truncate(T value); 322 | 323 | /// 324 | /// Compares two values and returns an integer that indicates whether the first value is less than, equal to, or greater than the second value. 325 | /// 326 | /// The first value to compare. 327 | /// The second value to compare. 328 | /// A signed integer that indicates the relative values of and , 329 | /// less than zero if is less than , 330 | /// zero if equals , 331 | /// and greater than zero if is greater than . 332 | int Compare(T left, T right); 333 | 334 | /// 335 | /// Gets the absolute value of a number. 336 | /// 337 | /// A number. 338 | /// The absolute value of . 339 | T Abs(T value); 340 | 341 | /// 342 | /// Returns the larger of two values. 343 | /// 344 | /// The first value to compare. 345 | /// The second value to compare. 346 | /// The or parameter, whichever is larger. 347 | T Max(T left, T right); 348 | 349 | /// 350 | /// Returns the smaller of two values. 351 | /// 352 | /// The first value to compare. 353 | /// The second value to compare. 354 | /// The or parameter, whichever is smaller. 355 | T Min(T left, T right); 356 | 357 | /// 358 | /// Gets a number that indicates the sign (negative, positive, or zero) of the current object. 359 | /// 360 | /// A number. 361 | /// A number that indicates the sign of the object, -1 if the value of this object 362 | /// is negative, 0 if the value of this object is zero (0), and 1 if the value of this object 363 | /// is positive. 364 | int Sign(T value); 365 | 366 | /// 367 | /// Converts the specified numeric value to its equivalent string representation by using the specified format and culture-specific format information. 368 | /// 369 | /// A number. 370 | /// A standard or custom numeric format string. 371 | /// An object that supplies culture-specific formatting information. 372 | /// The string representation of as specified by the and parameters. 373 | [return: NotNullIfNotNull("value")] 374 | string? ToString(T value, string? format, IFormatProvider? provider); 375 | 376 | /// 377 | /// Converts the specified numeric value to an . 378 | /// 379 | /// The value to convert. 380 | /// An object that contains the value of the parameter. 381 | sbyte ToSByte(T value); 382 | 383 | /// 384 | /// Converts the specified numeric value to an . 385 | /// 386 | /// The value to convert. 387 | /// An object that contains the value of the parameter. 388 | byte ToByte(T value); 389 | 390 | /// 391 | /// Converts the specified numeric value to an . 392 | /// 393 | /// The value to convert. 394 | /// An object that contains the value of the parameter. 395 | short ToInt16(T value); 396 | 397 | /// 398 | /// Converts the specified numeric value to an . 399 | /// 400 | /// The value to convert. 401 | /// An object that contains the value of the parameter. 402 | ushort ToUInt16(T value); 403 | 404 | /// 405 | /// Converts the specified numeric value to an . 406 | /// 407 | /// The value to convert. 408 | /// An object that contains the value of the parameter. 409 | int ToInt32(T value); 410 | 411 | /// 412 | /// Converts the specified numeric value to an . 413 | /// 414 | /// The value to convert. 415 | /// An object that contains the value of the parameter. 416 | uint ToUInt32(T value); 417 | 418 | /// 419 | /// Converts the specified numeric value to an . 420 | /// 421 | /// The value to convert. 422 | /// An object that contains the value of the parameter. 423 | long ToInt64(T value); 424 | 425 | /// 426 | /// Converts the specified numeric value to an . 427 | /// 428 | /// The value to convert. 429 | /// An object that contains the value of the parameter. 430 | ulong ToUInt64(T value); 431 | 432 | /// 433 | /// Converts the specified numeric value to a . 434 | /// 435 | /// The value to convert. 436 | /// An object that contains the value of the parameter. 437 | float ToSingle(T value); 438 | 439 | /// 440 | /// Converts the specified numeric value to a . 441 | /// 442 | /// The value to convert. 443 | /// An object that contains the value of the parameter. 444 | double ToDouble(T value); 445 | 446 | /// 447 | /// Converts the specified numeric value to a . 448 | /// 449 | /// The value to convert. 450 | /// An object that contains the value of the parameter. 451 | decimal ToDecimal(T value); 452 | 453 | /// 454 | /// Converts the specified numeric value to a . 455 | /// 456 | /// The value to convert. 457 | /// An object that contains the value of the parameter. 458 | BigInteger ToBigInteger(T value); 459 | 460 | /// 461 | /// Indicates whether the specified value is an even number. 462 | /// 463 | /// An integral number. 464 | /// true if is an even number; otherwise, false. 465 | bool IsEven(T value); 466 | 467 | /// 468 | /// Indicates whether the specified value is an odd number. 469 | /// 470 | /// An integral number. 471 | /// true if is an odd number; otherwise, false. 472 | bool IsOdd(T value); 473 | 474 | /// 475 | /// Indicates whether the specified integral value is a power of two. 476 | /// 477 | /// An integral number. 478 | /// true if is a power of two; otherwise, false. 479 | bool IsPowerOfTwo(T value); 480 | 481 | /// 482 | /// Returns clamped to the inclusive range of and . 483 | /// 484 | /// The value to be clamped. 485 | /// The lower bound of the result. 486 | /// The upper bound of the result. 487 | /// if is less than , 488 | /// if is greater than , 489 | /// else . 490 | T Clamp(T value, T min, T max); 491 | } 492 | } -------------------------------------------------------------------------------- /src/Genumerics/NullableAttributes.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #if !NULLABLE_ATTRIBUTES 6 | namespace System.Diagnostics.CodeAnalysis 7 | { 8 | #pragma warning disable IDE0021 // Use block body for constructors 9 | ///// Specifies that null is allowed as an input even if the corresponding type disallows it. 10 | //[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] 11 | //internal sealed class AllowNullAttribute : Attribute 12 | //{ } 13 | 14 | /// Specifies that null is disallowed as an input even if the corresponding type allows it. 15 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] 16 | internal sealed class DisallowNullAttribute : Attribute 17 | { } 18 | 19 | ///// Specifies that an output may be null even if the corresponding type disallows it. 20 | //[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] 21 | //internal sealed class MaybeNullAttribute : Attribute 22 | //{ } 23 | 24 | ///// Specifies that an output will not be null even if the corresponding type allows it. 25 | //[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] 26 | //internal sealed class NotNullAttribute : Attribute 27 | //{ } 28 | 29 | ///// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. 30 | //[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 31 | //internal sealed class MaybeNullWhenAttribute : Attribute 32 | //{ 33 | // /// Initializes the attribute with the specified return value condition. 34 | // /// 35 | // /// The return value condition. If the method returns this value, the associated parameter may be null. 36 | // /// 37 | // public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; 38 | 39 | // /// Gets the return value condition. 40 | // public bool ReturnValue { get; } 41 | //} 42 | 43 | ///// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. 44 | //[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 45 | //internal sealed class NotNullWhenAttribute : Attribute 46 | //{ 47 | // /// Initializes the attribute with the specified return value condition. 48 | // /// 49 | // /// The return value condition. If the method returns this value, the associated parameter will not be null. 50 | // /// 51 | // public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; 52 | 53 | // /// Gets the return value condition. 54 | // public bool ReturnValue { get; } 55 | //} 56 | 57 | /// Specifies that the output will be non-null if the named parameter is non-null. 58 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] 59 | internal sealed class NotNullIfNotNullAttribute : Attribute 60 | { 61 | /// Initializes the attribute with the associated parameter name. 62 | /// 63 | /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. 64 | /// 65 | public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; 66 | 67 | /// Gets the associated parameter name. 68 | public string ParameterName { get; } 69 | } 70 | 71 | ///// Applied to a method that will never return under any circumstance. 72 | //[AttributeUsage(AttributeTargets.Method, Inherited = false)] 73 | //internal sealed class DoesNotReturnAttribute : Attribute 74 | //{ } 75 | 76 | ///// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. 77 | //[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 78 | //internal sealed class DoesNotReturnIfAttribute : Attribute 79 | //{ 80 | // /// Initializes the attribute with the specified parameter value. 81 | // /// 82 | // /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to 83 | // /// the associated parameter matches this value. 84 | // /// 85 | // public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; 86 | 87 | // /// Gets the condition parameter value. 88 | // public bool ParameterValue { get; } 89 | //} 90 | #pragma warning restore IDE0021 // Use block body for constructors 91 | } 92 | #endif -------------------------------------------------------------------------------- /src/Genumerics/NullableNumericOperations.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Globalization; 28 | using System.Numerics; 29 | 30 | namespace Genumerics 31 | { 32 | /// 33 | /// Defines the numeric operations for a nullable numeric type. 34 | /// 35 | /// The numeric type. 36 | /// The numeric type's operations type. 37 | [CLSCompliant(false)] 38 | public readonly struct NullableNumericOperations : INumericOperations 39 | where T : struct 40 | where TNumericOperations : struct, INumericOperations 41 | { 42 | /// 43 | public T? Zero => default(TNumericOperations).Zero; 44 | 45 | /// 46 | public T? One => default(TNumericOperations).One; 47 | 48 | /// 49 | public T? MinusOne => default(TNumericOperations).MinusOne; 50 | 51 | /// 52 | public T? MaxValue => default(TNumericOperations).MaxValue; 53 | 54 | /// 55 | public T? MinValue => default(TNumericOperations).MinValue; 56 | 57 | /// 58 | public TypeCode TypeCode => default(TNumericOperations).TypeCode; 59 | 60 | /// 61 | public T? Add(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Add(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 62 | 63 | /// 64 | public T? BitwiseAnd(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).BitwiseAnd(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 65 | 66 | /// 67 | public T? Divide(T? dividend, T? divisor) => dividend.HasValue && divisor.HasValue ? default(TNumericOperations).Divide(dividend.GetValueOrDefault(), divisor.GetValueOrDefault()) : null; 68 | 69 | /// 70 | public T? DivRem(T? dividend, T? divisor, out T? remainder) 71 | { 72 | if (dividend.HasValue && divisor.HasValue) 73 | { 74 | var result = default(TNumericOperations).DivRem(dividend.GetValueOrDefault(), divisor.GetValueOrDefault(), out var r); 75 | remainder = r; 76 | return result; 77 | } 78 | remainder = null; 79 | return null; 80 | } 81 | 82 | /// 83 | public bool Equals(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Equals(left.GetValueOrDefault(), right.GetValueOrDefault()) : !left.HasValue && !right.HasValue; 84 | 85 | /// 86 | public bool GreaterThan(T? left, T? right) => left.HasValue && right.HasValue && default(TNumericOperations).GreaterThan(left.GetValueOrDefault(), right.GetValueOrDefault()); 87 | 88 | /// 89 | public bool GreaterThanOrEqual(T? left, T? right) => left.HasValue && right.HasValue && default(TNumericOperations).GreaterThanOrEqual(left.GetValueOrDefault(), right.GetValueOrDefault()); 90 | 91 | /// 92 | public T? LeftShift(T? value, int shift) => value.HasValue ? default(TNumericOperations).LeftShift(value.GetValueOrDefault(), shift) : value; 93 | 94 | /// 95 | public bool LessThan(T? left, T? right) => left.HasValue && right.HasValue && default(TNumericOperations).LessThan(left.GetValueOrDefault(), right.GetValueOrDefault()); 96 | 97 | /// 98 | public bool LessThanOrEqual(T? left, T? right) => left.HasValue && right.HasValue && default(TNumericOperations).LessThanOrEqual(left.GetValueOrDefault(), right.GetValueOrDefault()); 99 | 100 | /// 101 | public T? Multiply(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Multiply(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 102 | 103 | /// 104 | public T? Negate(T? value) => value.HasValue ? default(TNumericOperations).Negate(value.GetValueOrDefault()) : value; 105 | 106 | /// 107 | public T? OnesComplement(T? value) => value.HasValue ? default(TNumericOperations).OnesComplement(value.GetValueOrDefault()) : value; 108 | 109 | /// 110 | public bool NotEquals(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).NotEquals(left.GetValueOrDefault(), right.GetValueOrDefault()) : left.HasValue || right.HasValue; 111 | 112 | /// 113 | public T? BitwiseOr(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).BitwiseOr(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 114 | 115 | /// 116 | public T? Parse(string value, NumberStyles? styles, IFormatProvider? provider) => default(TNumericOperations).Parse(value, styles, provider); 117 | 118 | /// 119 | public T? Remainder(T? dividend, T? divisor) => dividend.HasValue && divisor.HasValue ? default(TNumericOperations).Remainder(dividend.GetValueOrDefault(), divisor.GetValueOrDefault()) : null; 120 | 121 | /// 122 | public T? RightShift(T? value, int shift) => value.HasValue ? default(TNumericOperations).RightShift(value.GetValueOrDefault(), shift) : value; 123 | 124 | /// 125 | public T? Subtract(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Subtract(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 126 | 127 | /// 128 | public bool TryParse(string? value, NumberStyles? styles, IFormatProvider? provider, out T? result) 129 | { 130 | var success = default(TNumericOperations).TryParse(value, styles, provider, out var r); 131 | result = r; 132 | return success; 133 | } 134 | 135 | #if SPAN 136 | /// 137 | public T? Parse(ReadOnlySpan value, NumberStyles? styles, IFormatProvider? provider) => default(TNumericOperations).Parse(value, styles, provider); 138 | 139 | /// 140 | public bool TryParse(ReadOnlySpan value, NumberStyles? styles, IFormatProvider? provider, out T? result) 141 | { 142 | var success = default(TNumericOperations).TryParse(value, styles, provider, out var r); 143 | result = r; 144 | return success; 145 | } 146 | 147 | /// 148 | public bool TryFormat(T? value, Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) 149 | { 150 | if (value.HasValue) 151 | { 152 | return default(TNumericOperations).TryFormat(value.GetValueOrDefault(), destination, out charsWritten, format, provider); 153 | } 154 | charsWritten = 0; 155 | return false; 156 | } 157 | #endif 158 | 159 | /// 160 | public T? Xor(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Xor(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 161 | 162 | /// 163 | public T? Convert(TFrom value) => value != null ? default(TNumericOperations).Convert(value) : null; 164 | 165 | /// 166 | public T? Round(T? value, int digits, MidpointRounding mode) => value.HasValue ? default(TNumericOperations).Round(value.GetValueOrDefault(), digits, mode) : value; 167 | 168 | /// 169 | public T? Floor(T? value) => value.HasValue ? default(TNumericOperations).Floor(value.GetValueOrDefault()) : value; 170 | 171 | /// 172 | public T? Ceiling(T? value) => value.HasValue ? default(TNumericOperations).Ceiling(value.GetValueOrDefault()) : value; 173 | 174 | /// 175 | public T? Truncate(T? value) => value.HasValue ? default(TNumericOperations).Truncate(value.GetValueOrDefault()) : value; 176 | 177 | /// 178 | public int Compare(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Compare(left.GetValueOrDefault(), right.GetValueOrDefault()) : (left.HasValue ? 1 : (right.HasValue ? -1 : 0)); 179 | 180 | /// 181 | public T? Abs(T? value) => value.HasValue ? default(TNumericOperations).Abs(value.GetValueOrDefault()) : value; 182 | 183 | /// 184 | public T? Max(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Max(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 185 | 186 | /// 187 | public T? Min(T? left, T? right) => left.HasValue && right.HasValue ? default(TNumericOperations).Min(left.GetValueOrDefault(), right.GetValueOrDefault()) : null; 188 | 189 | /// 190 | public int Sign(T? value) => value.HasValue ? default(TNumericOperations).Sign(value.GetValueOrDefault()) : -2; 191 | 192 | /// 193 | public string? ToString(T? value, string? format, IFormatProvider? provider) => value.HasValue ? default(TNumericOperations).ToString(value.GetValueOrDefault(), format, provider) : null; 194 | 195 | /// 196 | public sbyte ToSByte(T? value) => value.HasValue ? default(TNumericOperations).ToSByte(value.GetValueOrDefault()) : default; 197 | 198 | /// 199 | public byte ToByte(T? value) => value.HasValue ? default(TNumericOperations).ToByte(value.GetValueOrDefault()) : default; 200 | 201 | /// 202 | public short ToInt16(T? value) => value.HasValue ? default(TNumericOperations).ToInt16(value.GetValueOrDefault()) : default; 203 | 204 | /// 205 | public ushort ToUInt16(T? value) => value.HasValue ? default(TNumericOperations).ToUInt16(value.GetValueOrDefault()) : default; 206 | 207 | /// 208 | public int ToInt32(T? value) => value.HasValue ? default(TNumericOperations).ToInt32(value.GetValueOrDefault()) : default; 209 | 210 | /// 211 | public uint ToUInt32(T? value) => value.HasValue ? default(TNumericOperations).ToUInt32(value.GetValueOrDefault()) : default; 212 | 213 | /// 214 | public long ToInt64(T? value) => value.HasValue ? default(TNumericOperations).ToInt64(value.GetValueOrDefault()) : default; 215 | 216 | /// 217 | public ulong ToUInt64(T? value) => value.HasValue ? default(TNumericOperations).ToUInt64(value.GetValueOrDefault()) : default; 218 | 219 | /// 220 | public float ToSingle(T? value) => value.HasValue ? default(TNumericOperations).ToSingle(value.GetValueOrDefault()) : default; 221 | 222 | /// 223 | public double ToDouble(T? value) => value.HasValue ? default(TNumericOperations).ToDouble(value.GetValueOrDefault()) : default; 224 | 225 | /// 226 | public decimal ToDecimal(T? value) => value.HasValue ? default(TNumericOperations).ToDecimal(value.GetValueOrDefault()) : default; 227 | 228 | /// 229 | public BigInteger ToBigInteger(T? value) => value.HasValue ? default(TNumericOperations).ToBigInteger(value.GetValueOrDefault()) : default; 230 | 231 | /// 232 | public bool IsEven(T? value) => value.HasValue && default(TNumericOperations).IsEven(value.GetValueOrDefault()); 233 | 234 | /// 235 | public bool IsOdd(T? value) => value.HasValue && default(TNumericOperations).IsOdd(value.GetValueOrDefault()); 236 | 237 | /// 238 | public bool IsPowerOfTwo(T? value) => value.HasValue && default(TNumericOperations).IsPowerOfTwo(value.GetValueOrDefault()); 239 | 240 | /// 241 | public T? Clamp(T? value, T? min, T? max) => value.HasValue && min.HasValue && max.HasValue ? default(TNumericOperations).Clamp(value.GetValueOrDefault(), min.GetValueOrDefault(), max.GetValueOrDefault()) : null; 242 | 243 | /// 244 | public override bool Equals(object? obj) => obj is NullableNumericOperations; 245 | 246 | /// 247 | public override int GetHashCode() => nameof(NullableNumericOperations).GetHashCode(); 248 | 249 | #pragma warning disable IDE0060 // Remove unused parameter 250 | /// 251 | public static bool operator ==(NullableNumericOperations left, NullableNumericOperations right) => true; 252 | 253 | /// 254 | public static bool operator !=(NullableNumericOperations left, NullableNumericOperations right) => false; 255 | #pragma warning restore IDE0060 // Remove unused parameter 256 | } 257 | } -------------------------------------------------------------------------------- /src/Genumerics/Number`1.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Numerics; 28 | 29 | namespace Genumerics 30 | { 31 | /// 32 | /// A number wrapper type that provides numeric operations in the form of convenient type operators. 33 | /// 34 | /// The numeric type. 35 | public readonly struct Number : IEquatable>, IComparable>, IComparable, IFormattable, IConvertible 36 | { 37 | /// 38 | /// The numeric value. 39 | /// 40 | public T Value { get; } 41 | 42 | /// 43 | /// Number constructor. 44 | /// 45 | /// The numeric value. 46 | public Number(T value) 47 | { 48 | Value = value; 49 | } 50 | 51 | /// 52 | /// Returns the hash code for the current object. 53 | /// 54 | /// A 32-bit signed integer hash code. 55 | public override int GetHashCode() => Value?.GetHashCode() ?? 0; 56 | 57 | /// 58 | /// Converts the numeric value of the current object to its equivalent string representation. 59 | /// 60 | /// The string representation of the current numeric value. 61 | /// The type argument is not supported. 62 | public override string? ToString() => Number.GetOperationsInternal().ToString(Value, null, null); 63 | 64 | /// 65 | /// Converts the numeric value of the current numeric object to its equivalent string representation by using the specified format. 66 | /// 67 | /// A standard or custom numeric format string. 68 | /// The string representation of the current numeric value in the format specified by the parameter. 69 | /// The type argument is not supported. 70 | /// is not a valid format string. 71 | public string? ToString(string? format) => Number.GetOperationsInternal().ToString(Value, format, null); 72 | 73 | /// 74 | /// Converts the numeric value of the current numeric object to its equivalent string representation by using the specified culture-specific formatting information. 75 | /// 76 | /// An object that supplies culture-specific formatting information. 77 | /// The string representation of the current numeric value in the format specified by the parameter. 78 | /// The type argument is not supported. 79 | #pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes). 80 | public string? ToString(IFormatProvider? provider) => Number.GetOperationsInternal().ToString(Value, null, provider); 81 | #pragma warning restore CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes). 82 | 83 | /// 84 | /// Converts the numeric value of the current numeric object to its equivalent string representation by using the specified format and culture-specific format information. 85 | /// 86 | /// A standard or custom numeric format string. 87 | /// An object that supplies culture-specific formatting information. 88 | /// The string representation of the current numeric value as specified by the and parameters. 89 | /// The type argument is not supported. 90 | /// is not a valid format string. 91 | #pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes). 92 | public string? ToString(string? format, IFormatProvider? provider) => Number.GetOperationsInternal().ToString(Value, format, provider); 93 | #pragma warning restore CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes). 94 | 95 | #if SPAN 96 | /// 97 | /// Tries to convert the specified numeric value to its equivalent string representation into the destination by using the specified format and culture-specific format information. 98 | /// 99 | /// The to write the string representation to. 100 | /// The number of characters written to . 101 | /// A standard or custom numeric format string. 102 | /// An object that supplies culture-specific formatting information. 103 | /// true if the value's string representation was successfully written to ; otherwise, false. 104 | /// The type argument is not supported. 105 | public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) => Number.GetOperationsInternal().TryFormat(Value, destination, out charsWritten, format, provider); 106 | #endif 107 | 108 | /// 109 | /// Returns a value that indicates whether the current instance and a specified object have the same value. 110 | /// 111 | /// The object to compare. 112 | /// true if the argument is a object, and its value is equal to the value of the current instance; otherwise, false. 113 | /// The type argument is not supported. 114 | public override bool Equals(object? obj) => obj is Number n && Equals(n); 115 | 116 | /// 117 | /// Returns a value that indicates whether the current instance and a specified object have the same value. 118 | /// 119 | /// The object to compare. 120 | /// true if this numeric object and have the same value; otherwise, false. 121 | /// The type argument is not supported. 122 | public bool Equals(Number other) => Number.GetOperationsInternal().Equals(Value, other); 123 | 124 | /// 125 | /// Compares this instance to a specified object and returns an integer that indicates 126 | /// whether the value of this instance is less than, equal to, or greater than the 127 | /// value of the specified object. 128 | /// 129 | /// The object to compare. 130 | /// A signed integer that indicates the relative values of the current instance and , 131 | /// less than zero if current instance is less than , 132 | /// zero if current instance equals , 133 | /// and greater than zero if current instance is greater than or is null. 134 | /// The type argument is not supported. 135 | public int CompareTo(object? obj) => obj is Number n ? CompareTo(n) : (Value == null ? 0 : 1); 136 | 137 | /// 138 | /// Compares this instance to a specified object and returns an integer that indicates 139 | /// whether the value of this instance is less than, equal to, or greater than the 140 | /// value of the specified object. 141 | /// 142 | /// The object to compare. 143 | /// A signed integer that indicates the relative values of the current instance and , 144 | /// less than zero if current instance is less than , 145 | /// zero if current instance equals , 146 | /// and greater than zero if current instance is greater than . 147 | public int CompareTo(Number other) => Number.GetOperationsInternal().Compare(Value, other); 148 | 149 | /// 150 | /// Converts the number to its equivalent. 151 | /// 152 | /// The numeric type to convert to. 153 | /// A value that is equivalent to the number. 154 | /// One or both type arguments provided are not supported. 155 | /// Number is greater than 's MaxValue or less than 's MinValue. 156 | public TTo To() => Number.GetOperationsInternal().Convert(Value); 157 | 158 | /// 159 | /// Returns the for . 160 | /// 161 | /// The for . 162 | /// The type argument is not supported. 163 | public TypeCode GetTypeCode() => Number.GetOperationsInternal().TypeCode; 164 | 165 | bool IConvertible.ToBoolean(IFormatProvider? provider) => Convert.ToBoolean(Value, provider); 166 | 167 | byte IConvertible.ToByte(IFormatProvider? provider) => Number.GetOperationsInternal().ToByte(Value); 168 | 169 | char IConvertible.ToChar(IFormatProvider? provider) => Convert.ToChar(Value, provider); 170 | 171 | DateTime IConvertible.ToDateTime(IFormatProvider? provider) => Convert.ToDateTime(Value, provider); 172 | 173 | decimal IConvertible.ToDecimal(IFormatProvider? provider) => Number.GetOperationsInternal().ToDecimal(Value); 174 | 175 | double IConvertible.ToDouble(IFormatProvider? provider) => Number.GetOperationsInternal().ToDouble(Value); 176 | 177 | short IConvertible.ToInt16(IFormatProvider? provider) => Number.GetOperationsInternal().ToInt16(Value); 178 | 179 | int IConvertible.ToInt32(IFormatProvider? provider) => Number.GetOperationsInternal().ToInt32(Value); 180 | 181 | long IConvertible.ToInt64(IFormatProvider? provider) => Number.GetOperationsInternal().ToInt64(Value); 182 | 183 | sbyte IConvertible.ToSByte(IFormatProvider? provider) => Number.GetOperationsInternal().ToSByte(Value); 184 | 185 | float IConvertible.ToSingle(IFormatProvider? provider) => Number.GetOperationsInternal().ToSingle(Value); 186 | 187 | #pragma warning disable CS8768 // Nullability of reference types in return type doesn't match implemented member (possibly because of nullability attributes). 188 | object? IConvertible.ToType(Type conversionType, IFormatProvider? provider) => Convert.ChangeType(Value, conversionType, provider); 189 | #pragma warning restore CS8768 // Nullability of reference types in return type doesn't match implemented member (possibly because of nullability attributes). 190 | 191 | ushort IConvertible.ToUInt16(IFormatProvider? provider) => Number.GetOperationsInternal().ToUInt16(Value); 192 | 193 | uint IConvertible.ToUInt32(IFormatProvider? provider) => Number.GetOperationsInternal().ToUInt32(Value); 194 | 195 | ulong IConvertible.ToUInt64(IFormatProvider? provider) => Number.GetOperationsInternal().ToUInt64(Value); 196 | 197 | /// 198 | /// Defines an implicit conversion of a to a . 199 | /// 200 | /// The value to convert to a . 201 | public static implicit operator Number(T value) => new(value); 202 | 203 | /// 204 | /// Defines an implicit conversion of a to a . 205 | /// 206 | /// The value to convert to a . 207 | public static implicit operator T(Number value) => value.Value; 208 | 209 | /// 210 | /// Returns the value of the numeric operand. (The sign of the operand is unchanged.) 211 | /// 212 | /// A numeric value. 213 | /// The value of the operand. 214 | /// The type argument is not supported. 215 | public static Number operator +(Number value) => value; 216 | 217 | /// 218 | /// Adds the values of two specified numeric objects. 219 | /// 220 | /// The first value to add. 221 | /// The second value to add. 222 | /// The sum of and . 223 | /// The type argument is not supported. 224 | public static Number operator +(Number left, Number right) => Number.Add(left, right); 225 | 226 | /// 227 | /// Negates a specified numeric value. 228 | /// 229 | /// The value to negate. 230 | /// The result of the value parameter multiplied by negative one (-1). 231 | /// The type argument is not supported. 232 | /// -or- 233 | /// the numeric type doesn't support negative values. 234 | public static Number operator -(Number value) => Number.Negate(value); 235 | 236 | /// 237 | /// Subtracts a numeric value from another numeric value. 238 | /// 239 | /// The value to subtract from (the minuend). 240 | /// The value to subtract (the subtrahend). 241 | /// The result of subtracting from . 242 | /// The type argument is not supported. 243 | public static Number operator -(Number left, Number right) => Number.Subtract(left, right); 244 | 245 | /// 246 | /// Returns the bitwise one's complement of a numeric value. 247 | /// 248 | /// An integer value. 249 | /// The bitwise one's complement of . 250 | /// The type argument is not supported. 251 | /// -or- 252 | /// the numeric type is a floating point type. 253 | public static Number operator ~(Number value) => Number.OnesComplement(value); 254 | 255 | /// 256 | /// Increments a numeric value by 1. 257 | /// 258 | /// The value to increment. 259 | /// The value of the parameter incremented by 1. 260 | /// The type argument is not supported. 261 | public static Number operator ++(Number value) => Number.Add(value, Number.One()); 262 | 263 | /// 264 | /// Decrements a numeric value by 1. 265 | /// 266 | /// The value to decrement. 267 | /// The value of the parameter decremented by 1. 268 | /// The type argument is not supported. 269 | public static Number operator --(Number value) => Number.Subtract(value, Number.One()); 270 | 271 | /// 272 | /// Multiplies two specified numeric values. 273 | /// 274 | /// The first value to multiply. 275 | /// The second value to multiply. 276 | /// The product of and . 277 | /// The type argument is not supported. 278 | public static Number operator *(Number left, Number right) => Number.Multiply(left, right); 279 | 280 | /// 281 | /// Divides a specified numeric value by another specified numeric value. 282 | /// 283 | /// The value to be divided. 284 | /// The value to divide by. 285 | /// The result of the division. 286 | /// The type argument is not supported. 287 | /// is zero (0). 288 | public static Number operator /(Number dividend, Number divisor) => Number.Divide(dividend, divisor); 289 | 290 | /// 291 | /// Returns the remainder that results from division with two specified numeric values. 292 | /// 293 | /// The value to be divided. 294 | /// The value to divide by. 295 | /// The remainder that results from the division. 296 | /// The type argument is not supported. 297 | /// is zero (0). 298 | public static Number operator %(Number dividend, Number divisor) => Number.Remainder(dividend, divisor); 299 | 300 | /// 301 | /// Performs a bitwise And operation on two integral values. 302 | /// 303 | /// The first value. 304 | /// The second value. 305 | /// The result of the bitwise And operation. 306 | /// The type argument is not supported. 307 | /// -or- 308 | /// the numeric type is a floating point type. 309 | public static Number operator &(Number left, Number right) => Number.BitwiseAnd(left, right); 310 | 311 | /// 312 | /// Performs a bitwise Or operation on two integral values. 313 | /// 314 | /// The first value. 315 | /// The second value. 316 | /// The result of the bitwise Or operation. 317 | /// The type argument is not supported. 318 | /// -or- 319 | /// the numeric type is a floating point type. 320 | public static Number operator |(Number left, Number right) => Number.BitwiseOr(left, right); 321 | 322 | /// 323 | /// Performs a bitwise exclusive Or operation on two integral values. 324 | /// 325 | /// The first value. 326 | /// The second value. 327 | /// The result of the bitwise exclusive Or operation. 328 | /// The type argument is not supported. 329 | /// -or- 330 | /// the numeric type is a floating point type. 331 | public static Number operator ^(Number left, Number right) => Number.Xor(left, right); 332 | 333 | /// 334 | /// Shifts an integral value a specified number of bits to the left. 335 | /// 336 | /// The value whose bits are to be shifted. 337 | /// The number of bits to shift value to the left. 338 | /// A value that has been shifted to the left by the specified number of bits. 339 | /// The type argument is not supported. 340 | /// -or- 341 | /// the numeric type is a floating point type. 342 | public static Number operator <<(Number value, int shift) => Number.LeftShift(value, shift); 343 | 344 | /// 345 | /// Shifts an integral value a specified number of bits to the right. 346 | /// 347 | /// The value whose bits are to be shifted. 348 | /// The number of bits to shift value to the right. 349 | /// A value that has been shifted to the right by the specified number of bits. 350 | /// The type argument is not supported. 351 | /// -or- 352 | /// the numeric type is a floating point type. 353 | public static Number operator >>(Number value, int shift) => Number.RightShift(value, shift); 354 | 355 | /// 356 | /// Returns a value that indicates whether the values of two numeric objects are equal. 357 | /// 358 | /// The first value to compare. 359 | /// The second value to compare. 360 | /// true if the and parameters have the same value; otherwise, false. 361 | /// The type argument is not supported. 362 | public static bool operator ==(Number left, Number right) => Number.Equals(left, right); 363 | 364 | /// 365 | /// Returns a value that indicates whether two numeric objects have different values. 366 | /// 367 | /// The first value to compare. 368 | /// The second value to compare. 369 | /// true if and are not equal; otherwise, false. 370 | /// The type argument is not supported. 371 | public static bool operator !=(Number left, Number right) => Number.NotEquals(left, right); 372 | 373 | /// 374 | /// Returns a value that indicates whether a numeric value is less than another numeric value. 375 | /// 376 | /// The first value to compare. 377 | /// The second value to compare. 378 | /// true if is less than ; otherwise, false. 379 | /// The type argument is not supported. 380 | public static bool operator <(Number left, Number right) => Number.LessThan(left, right); 381 | 382 | /// 383 | /// Returns a value that indicates whether a numeric value is greater than another numeric value. 384 | /// 385 | /// The first value to compare. 386 | /// The second value to compare. 387 | /// true if is greater than ; otherwise, false. 388 | /// The type argument is not supported. 389 | public static bool operator >(Number left, Number right) => Number.GreaterThan(left, right); 390 | 391 | /// 392 | /// Returns a value that indicates whether a numeric value is less than or equal to another numeric value. 393 | /// 394 | /// The first value to compare. 395 | /// The second value to compare. 396 | /// true if is less than or equal to ; otherwise, false. 397 | /// The type argument is not supported. 398 | public static bool operator <=(Number left, Number right) => Number.LessThanOrEqual(left, right); 399 | 400 | /// 401 | /// Returns a value that indicates whether a numeric value is greater than or equal to another numeric value. 402 | /// 403 | /// The first value to compare. 404 | /// The second value to compare. 405 | /// true if is greater than ; otherwise, false. 406 | /// The type argument is not supported. 407 | public static bool operator >=(Number left, Number right) => Number.GreaterThanOrEqual(left, right); 408 | 409 | /// 410 | /// Defines an explicit conversion of an to a value. 411 | /// 412 | /// The value to convert to a . 413 | /// An object that contains the value of the parameter. 414 | /// The type argument is not supported. 415 | /// is greater than 's MaxValue or less than 's MinValue. 416 | public static explicit operator Number(byte value) => Number.GetOperationsInternal().Convert(value); 417 | 418 | /// 419 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 420 | /// 421 | /// The value to convert to a . 422 | /// An object that contains the value of the parameter. 423 | /// The type argument is not supported. 424 | /// is greater than 's MaxValue or less than 's MinValue. 425 | [CLSCompliant(false)] 426 | public static explicit operator Number(sbyte value) => Number.GetOperationsInternal().Convert(value); 427 | 428 | /// 429 | /// Defines an explicit conversion of an to a value. 430 | /// 431 | /// The value to convert to a . 432 | /// An object that contains the value of the parameter. 433 | /// The type argument is not supported. 434 | /// is greater than 's MaxValue or less than 's MinValue. 435 | public static explicit operator Number(short value) => Number.GetOperationsInternal().Convert(value); 436 | 437 | /// 438 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 439 | /// 440 | /// The value to convert to a . 441 | /// An object that contains the value of the parameter. 442 | /// The type argument is not supported. 443 | /// is greater than 's MaxValue or less than 's MinValue. 444 | [CLSCompliant(false)] 445 | public static explicit operator Number(ushort value) => Number.GetOperationsInternal().Convert(value); 446 | 447 | /// 448 | /// Defines an explicit conversion of an to a value. 449 | /// 450 | /// The value to convert to a . 451 | /// An object that contains the value of the parameter. 452 | /// The type argument is not supported. 453 | /// is greater than 's MaxValue or less than 's MinValue. 454 | public static explicit operator Number(int value) => Number.GetOperationsInternal().Convert(value); 455 | 456 | /// 457 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 458 | /// 459 | /// The value to convert to a . 460 | /// An object that contains the value of the parameter. 461 | /// The type argument is not supported. 462 | /// is greater than 's MaxValue or less than 's MinValue. 463 | [CLSCompliant(false)] 464 | public static explicit operator Number(uint value) => Number.GetOperationsInternal().Convert(value); 465 | 466 | /// 467 | /// Defines an explicit conversion of an to a value. 468 | /// 469 | /// The value to convert to a . 470 | /// An object that contains the value of the parameter. 471 | /// The type argument is not supported. 472 | /// is greater than 's MaxValue or less than 's MinValue. 473 | public static explicit operator Number(long value) => Number.GetOperationsInternal().Convert(value); 474 | 475 | /// 476 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 477 | /// 478 | /// The value to convert to a . 479 | /// An object that contains the value of the parameter. 480 | /// The type argument is not supported. 481 | /// is greater than 's MaxValue or less than 's MinValue. 482 | [CLSCompliant(false)] 483 | public static explicit operator Number(ulong value) => Number.GetOperationsInternal().Convert(value); 484 | 485 | /// 486 | /// Defines an explicit conversion of a value to a value. 487 | /// 488 | /// The value to convert to a . 489 | /// An object that contains the value of the parameter. 490 | /// The type argument is not supported. 491 | /// is greater than 's MaxValue or less than 's MinValue. 492 | public static explicit operator Number(float value) => Number.GetOperationsInternal().Convert(value); 493 | 494 | /// 495 | /// Defines an explicit conversion of a value to a value. 496 | /// 497 | /// The value to convert to a . 498 | /// An object that contains the value of the parameter. 499 | /// The type argument is not supported. 500 | /// is greater than 's MaxValue or less than 's MinValue. 501 | public static explicit operator Number(double value) => Number.GetOperationsInternal().Convert(value); 502 | 503 | /// 504 | /// Defines an explicit conversion of a value to a value. 505 | /// 506 | /// The value to convert to a . 507 | /// An object that contains the value of the parameter. 508 | /// The type argument is not supported. 509 | /// is greater than 's MaxValue or less than 's MinValue. 510 | public static explicit operator Number(decimal value) => Number.GetOperationsInternal().Convert(value); 511 | 512 | /// 513 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 514 | /// 515 | /// The value to convert to an . 516 | /// An object that contains the value of the parameter. 517 | /// The type argument is not supported. 518 | /// is greater than 's MaxValue or less than 's MinValue. 519 | [CLSCompliant(false)] 520 | public static explicit operator sbyte(Number value) => Number.GetOperationsInternal().ToSByte(value); 521 | 522 | /// 523 | /// Defines an explicit conversion of a object to an value. 524 | /// 525 | /// The value to convert to an . 526 | /// An object that contains the value of the parameter. 527 | /// The type argument is not supported. 528 | /// is greater than 's MaxValue or less than 's MinValue. 529 | public static explicit operator byte(Number value) => Number.GetOperationsInternal().ToByte(value); 530 | 531 | /// 532 | /// Defines an explicit conversion of a object to an value. 533 | /// 534 | /// The value to convert to an . 535 | /// An object that contains the value of the parameter. 536 | /// The type argument is not supported. 537 | /// is greater than 's MaxValue or less than 's MinValue. 538 | public static explicit operator short(Number value) => Number.GetOperationsInternal().ToInt16(value); 539 | 540 | /// 541 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 542 | /// 543 | /// The value to convert to an . 544 | /// An object that contains the value of the parameter. 545 | /// The type argument is not supported. 546 | /// is greater than 's MaxValue or less than 's MinValue. 547 | [CLSCompliant(false)] 548 | public static explicit operator ushort(Number value) => Number.GetOperationsInternal().ToUInt16(value); 549 | 550 | /// 551 | /// Defines an explicit conversion of a object to an value. 552 | /// 553 | /// The value to convert to an . 554 | /// An object that contains the value of the parameter. 555 | /// The type argument is not supported. 556 | /// is greater than 's MaxValue or less than 's MinValue. 557 | public static explicit operator int(Number value) => Number.GetOperationsInternal().ToInt32(value); 558 | 559 | /// 560 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 561 | /// 562 | /// The value to convert to an . 563 | /// An object that contains the value of the parameter. 564 | /// The type argument is not supported. 565 | /// is greater than 's MaxValue or less than 's MinValue. 566 | [CLSCompliant(false)] 567 | public static explicit operator uint(Number value) => Number.GetOperationsInternal().ToUInt32(value); 568 | 569 | /// 570 | /// Defines an explicit conversion of a object to an value. 571 | /// 572 | /// The value to convert to an . 573 | /// An object that contains the value of the parameter. 574 | /// The type argument is not supported. 575 | /// is greater than 's MaxValue or less than 's MinValue. 576 | public static explicit operator long(Number value) => Number.GetOperationsInternal().ToInt64(value); 577 | 578 | /// 579 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 580 | /// 581 | /// The value to convert to an . 582 | /// An object that contains the value of the parameter. 583 | /// The type argument is not supported. 584 | /// is greater than 's MaxValue or less than 's MinValue. 585 | [CLSCompliant(false)] 586 | public static explicit operator ulong(Number value) => Number.GetOperationsInternal().ToUInt64(value); 587 | 588 | /// 589 | /// Defines an explicit conversion of a object to an value. 590 | /// 591 | /// The value to convert to an . 592 | /// An object that contains the value of the parameter. 593 | /// The type argument is not supported. 594 | /// is greater than 's MaxValue or less than 's MinValue. 595 | public static explicit operator float(Number value) => Number.GetOperationsInternal().ToSingle(value); 596 | 597 | /// 598 | /// Defines an explicit conversion of a object to an value. 599 | /// 600 | /// The value to convert to an . 601 | /// An object that contains the value of the parameter. 602 | /// The type argument is not supported. 603 | /// is greater than 's MaxValue or less than 's MinValue. 604 | public static explicit operator double(Number value) => Number.GetOperationsInternal().ToDouble(value); 605 | 606 | /// 607 | /// Defines an explicit conversion of a object to an value. 608 | /// 609 | /// The value to convert to an . 610 | /// An object that contains the value of the parameter. 611 | /// The type argument is not supported. 612 | /// is greater than 's MaxValue or less than 's MinValue. 613 | public static explicit operator decimal(Number value) => Number.GetOperationsInternal().ToDecimal(value); 614 | 615 | /// 616 | /// Defines an explicit conversion of a to a value. 617 | /// 618 | /// The value to convert to a . 619 | /// An object that contains the value of the parameter. 620 | /// The type argument is not supported. 621 | /// is greater than 's MaxValue or less than 's MinValue. 622 | public static explicit operator Number(BigInteger value) => Number.GetOperationsInternal().Convert(value); 623 | 624 | /// 625 | /// Defines an explicit conversion of a object to a value. 626 | /// 627 | /// The value to convert to a . 628 | /// An object that contains the value of the parameter. 629 | /// The type argument is not supported. 630 | public static explicit operator BigInteger(Number value) => Number.GetOperationsInternal().ToBigInteger(value); 631 | 632 | /// 633 | /// Defines an explicit conversion of a to a value. 634 | /// 635 | /// The value to convert to a . 636 | /// An object that contains the value of the parameter. 637 | /// The type argument is not supported. 638 | /// is greater than 's MaxValue or less than 's MinValue. 639 | public static explicit operator Number(nint value) => Number.GetOperationsInternal().Convert(value); 640 | 641 | /// 642 | /// Defines an explicit conversion of a object to an value. 643 | /// 644 | /// The value to convert to an . 645 | /// An object that contains the value of the parameter. 646 | /// The type argument is not supported. 647 | public static explicit operator nint(Number value) => Number.GetOperationsInternal().Convert(value.Value); 648 | 649 | /// 650 | /// Defines an explicit conversion of a to a value. 651 | /// 652 | /// The value to convert to a . 653 | /// An object that contains the value of the parameter. 654 | /// The type argument is not supported. 655 | /// is greater than 's MaxValue or less than 's MinValue. 656 | [CLSCompliant(false)] 657 | public static explicit operator Number(nuint value) => Number.GetOperationsInternal().Convert(value); 658 | 659 | /// 660 | /// Defines an explicit conversion of a object to an value. 661 | /// 662 | /// The value to convert to an . 663 | /// An object that contains the value of the parameter. 664 | /// The type argument is not supported. 665 | [CLSCompliant(false)] 666 | public static explicit operator nuint(Number value) => Number.GetOperationsInternal().Convert(value.Value); 667 | } 668 | } -------------------------------------------------------------------------------- /src/Genumerics/Number`2.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Numerics; 28 | 29 | namespace Genumerics 30 | { 31 | /// 32 | /// A high performance number wrapper type that provides numeric operations in the form of convenient type operators. 33 | /// 34 | /// The numeric type. 35 | /// The numeric operations type.+ 36 | [CLSCompliant(false)] 37 | public readonly struct Number : IEquatable>, IComparable>, IComparable, IFormattable, IConvertible 38 | where TNumericOperations : struct, INumericOperations 39 | { 40 | /// 41 | /// The numeric value. 42 | /// 43 | public T Value { get; } 44 | 45 | /// 46 | /// Number constructor. 47 | /// 48 | /// The numeric value. 49 | public Number(T value) 50 | { 51 | Value = value; 52 | } 53 | 54 | /// 55 | /// Returns the hash code for the current object. 56 | /// 57 | /// A 32-bit signed integer hash code. 58 | public override int GetHashCode() => Value?.GetHashCode() ?? 0; 59 | 60 | /// 61 | /// Converts the numeric value of the current object to its equivalent string representation. 62 | /// 63 | /// The string representation of the current numeric value. 64 | public override string ToString() => default(TNumericOperations).ToString(Value, null, null)!; 65 | 66 | /// 67 | /// Converts the numeric value of the current numeric object to its equivalent string representation by using the specified format. 68 | /// 69 | /// A standard or custom numeric format string. 70 | /// The string representation of the current numeric value in the format specified by the parameter. 71 | /// is not a valid format string. 72 | public string ToString(string? format) => default(TNumericOperations).ToString(Value, format, null)!; 73 | 74 | /// 75 | /// Converts the numeric value of the current numeric object to its equivalent string representation by using the specified culture-specific formatting information. 76 | /// 77 | /// An object that supplies culture-specific formatting information. 78 | /// The string representation of the current numeric value in the format specified by the parameter. 79 | public string ToString(IFormatProvider? provider) => default(TNumericOperations).ToString(Value, null, provider)!; 80 | 81 | /// 82 | /// Converts the numeric value of the current numeric object to its equivalent string representation by using the specified format and culture-specific format information. 83 | /// 84 | /// A standard or custom numeric format string. 85 | /// An object that supplies culture-specific formatting information. 86 | /// The string representation of the current numeric value as specified by the and parameters. 87 | /// is not a valid format string. 88 | public string ToString(string? format, IFormatProvider? provider) => default(TNumericOperations).ToString(Value, format, provider)!; 89 | 90 | #if SPAN 91 | /// 92 | /// Tries to convert the specified numeric value to its equivalent string representation into the destination by using the specified format and culture-specific format information. 93 | /// 94 | /// The to write the string representation to. 95 | /// The number of characters written to . 96 | /// A standard or custom numeric format string. 97 | /// An object that supplies culture-specific formatting information. 98 | /// true if the value's string representation was successfully written to ; otherwise, false. 99 | public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) => default(TNumericOperations).TryFormat(Value, destination, out charsWritten, format, provider); 100 | #endif 101 | 102 | /// 103 | /// Returns a value that indicates whether the current instance and a specified object have the same value. 104 | /// 105 | /// The object to compare. 106 | /// true if the argument is a object, and its value is equal to the value of the current instance; otherwise, false. 107 | public override bool Equals(object? obj) => obj is Number n && Equals(n); 108 | 109 | /// 110 | /// Returns a value that indicates whether the current instance and a specified object have the same value. 111 | /// 112 | /// The object to compare. 113 | /// true if this numeric object and have the same value; otherwise, false. 114 | public bool Equals(Number other) => default(TNumericOperations).Equals(Value, other); 115 | 116 | /// 117 | /// Compares this instance to a specified object and returns an integer that indicates 118 | /// whether the value of this instance is less than, equal to, or greater than the 119 | /// value of the specified object. 120 | /// 121 | /// The object to compare. 122 | /// A signed integer that indicates the relative values of the current instance and , 123 | /// less than zero if current instance is less than , 124 | /// zero if current instance equals , 125 | /// and greater than zero if current instance is greater than or is null. 126 | public int CompareTo(object? obj) => obj is Number n ? CompareTo(n) : (Value == null ? 0 : 1); 127 | 128 | /// 129 | /// Compares this instance to a specified object and returns an integer that indicates 130 | /// whether the value of this instance is less than, equal to, or greater than the 131 | /// value of the specified object. 132 | /// 133 | /// The object to compare. 134 | /// A signed integer that indicates the relative values of the current instance and , 135 | /// less than zero if current instance is less than , 136 | /// zero if current instance equals , 137 | /// and greater than zero if current instance is greater than . 138 | public int CompareTo(Number other) => default(TNumericOperations).Compare(Value, other); 139 | 140 | /// 141 | /// Converts the number to its equivalent. 142 | /// 143 | /// The numeric type to convert to. 144 | /// A value that is equivalent to the number. 145 | /// The type argument provided is not supported. 146 | /// Number is greater than 's MaxValue or less than 's MinValue. 147 | public TTo To() => Number.GetOperationsInternal().Convert(Value); 148 | 149 | /// 150 | /// Returns the for . 151 | /// 152 | /// The for . 153 | public TypeCode GetTypeCode() => default(TNumericOperations).TypeCode; 154 | 155 | bool IConvertible.ToBoolean(IFormatProvider? provider) => Convert.ToBoolean(Value, provider); 156 | 157 | byte IConvertible.ToByte(IFormatProvider? provider) => default(TNumericOperations).ToByte(Value); 158 | 159 | char IConvertible.ToChar(IFormatProvider? provider) => Convert.ToChar(Value, provider); 160 | 161 | DateTime IConvertible.ToDateTime(IFormatProvider? provider) => Convert.ToDateTime(Value, provider); 162 | 163 | decimal IConvertible.ToDecimal(IFormatProvider? provider) => default(TNumericOperations).ToDecimal(Value); 164 | 165 | double IConvertible.ToDouble(IFormatProvider? provider) => default(TNumericOperations).ToDouble(Value); 166 | 167 | short IConvertible.ToInt16(IFormatProvider? provider) => default(TNumericOperations).ToInt16(Value); 168 | 169 | int IConvertible.ToInt32(IFormatProvider? provider) => default(TNumericOperations).ToInt32(Value); 170 | 171 | long IConvertible.ToInt64(IFormatProvider? provider) => default(TNumericOperations).ToInt64(Value); 172 | 173 | sbyte IConvertible.ToSByte(IFormatProvider? provider) => default(TNumericOperations).ToSByte(Value); 174 | 175 | float IConvertible.ToSingle(IFormatProvider? provider) => default(TNumericOperations).ToSingle(Value); 176 | 177 | #pragma warning disable CS8768 // Nullability of reference types in return type doesn't match implemented member (possibly because of nullability attributes). 178 | object? IConvertible.ToType(Type conversionType, IFormatProvider? provider) => Convert.ChangeType(Value, conversionType, provider); 179 | #pragma warning restore CS8768 // Nullability of reference types in return type doesn't match implemented member (possibly because of nullability attributes). 180 | 181 | ushort IConvertible.ToUInt16(IFormatProvider? provider) => default(TNumericOperations).ToUInt16(Value); 182 | 183 | uint IConvertible.ToUInt32(IFormatProvider? provider) => default(TNumericOperations).ToUInt32(Value); 184 | 185 | ulong IConvertible.ToUInt64(IFormatProvider? provider) => default(TNumericOperations).ToUInt64(Value); 186 | 187 | /// 188 | /// Defines an implicit conversion of a to a . 189 | /// 190 | /// The value to convert to a . 191 | public static implicit operator Number(T value) => new(value); 192 | 193 | /// 194 | /// Defines an implicit conversion of a to a . 195 | /// 196 | /// The value to convert to a . 197 | public static implicit operator T(Number value) => value.Value; 198 | 199 | /// 200 | /// Returns the value of the numeric operand. (The sign of the operand is unchanged.) 201 | /// 202 | /// A numeric value. 203 | /// The value of the operand. 204 | public static Number operator +(Number value) => value; 205 | 206 | /// 207 | /// Adds the values of two specified numeric objects. 208 | /// 209 | /// The first value to add. 210 | /// The second value to add. 211 | /// The sum of and . 212 | public static Number operator +(Number left, Number right) => default(TNumericOperations).Add(left, right); 213 | 214 | /// 215 | /// Negates a specified numeric value. 216 | /// 217 | /// The value to negate. 218 | /// The result of the value parameter multiplied by negative one (-1). 219 | /// The numeric type doesn't support negative values. 220 | public static Number operator -(Number value) => default(TNumericOperations).Negate(value); 221 | 222 | /// 223 | /// Subtracts a numeric value from another numeric value. 224 | /// 225 | /// The value to subtract from (the minuend). 226 | /// The value to subtract (the subtrahend). 227 | /// The result of subtracting from . 228 | public static Number operator -(Number left, Number right) => default(TNumericOperations).Subtract(left, right); 229 | 230 | /// 231 | /// Returns the bitwise one's complement of a numeric value. 232 | /// 233 | /// An integer value. 234 | /// The bitwise one's complement of . 235 | /// The numeric type is a floating point type. 236 | public static Number operator ~(Number value) => default(TNumericOperations).OnesComplement(value); 237 | 238 | /// 239 | /// Increments a numeric value by 1. 240 | /// 241 | /// The value to increment. 242 | /// The value of the parameter incremented by 1. 243 | public static Number operator ++(Number value) => default(TNumericOperations).Add(value, default(TNumericOperations).One); 244 | 245 | /// 246 | /// Decrements a numeric value by 1. 247 | /// 248 | /// The value to decrement. 249 | /// The value of the parameter decremented by 1. 250 | public static Number operator --(Number value) => default(TNumericOperations).Subtract(value, default(TNumericOperations).One); 251 | 252 | /// 253 | /// Multiplies two specified numeric values. 254 | /// 255 | /// The first value to multiply. 256 | /// The second value to multiply. 257 | /// The product of and . 258 | public static Number operator *(Number left, Number right) => default(TNumericOperations).Multiply(left, right); 259 | 260 | /// 261 | /// Divides a specified numeric value by another specified numeric value. 262 | /// 263 | /// The value to be divided. 264 | /// The value to divide by. 265 | /// The result of the division. 266 | /// is zero (0). 267 | public static Number operator /(Number dividend, Number divisor) => default(TNumericOperations).Divide(dividend, divisor); 268 | 269 | /// 270 | /// Returns the remainder that results from division with two specified numeric values. 271 | /// 272 | /// The value to be divided. 273 | /// The value to divide by. 274 | /// The remainder that results from the division. 275 | /// is zero (0). 276 | public static Number operator %(Number dividend, Number divisor) => default(TNumericOperations).Remainder(dividend, divisor); 277 | 278 | /// 279 | /// Performs a bitwise And operation on two integral values. 280 | /// 281 | /// The first value. 282 | /// The second value. 283 | /// The result of the bitwise And operation. 284 | /// The numeric type is a floating point type. 285 | public static Number operator &(Number left, Number right) => default(TNumericOperations).BitwiseAnd(left, right); 286 | 287 | /// 288 | /// Performs a bitwise Or operation on two integral values. 289 | /// 290 | /// The first value. 291 | /// The second value. 292 | /// The result of the bitwise Or operation. 293 | /// The numeric type is a floating point type. 294 | public static Number operator |(Number left, Number right) => default(TNumericOperations).BitwiseOr(left, right); 295 | 296 | /// 297 | /// Performs a bitwise exclusive Or operation on two integral values. 298 | /// 299 | /// The first value. 300 | /// The second value. 301 | /// The result of the bitwise exclusive Or operation. 302 | /// The numeric type is a floating point type. 303 | public static Number operator ^(Number left, Number right) => default(TNumericOperations).Xor(left, right); 304 | 305 | /// 306 | /// Shifts an integral value a specified number of bits to the left. 307 | /// 308 | /// The value whose bits are to be shifted. 309 | /// The number of bits to shift value to the left. 310 | /// A value that has been shifted to the left by the specified number of bits. 311 | /// The numeric type is a floating point type. 312 | public static Number operator <<(Number value, int shift) => default(TNumericOperations).LeftShift(value, shift); 313 | 314 | /// 315 | /// Shifts an integral value a specified number of bits to the right. 316 | /// 317 | /// The value whose bits are to be shifted. 318 | /// The number of bits to shift value to the right. 319 | /// A value that has been shifted to the right by the specified number of bits. 320 | /// The numeric type is a floating point type. 321 | public static Number operator >>(Number value, int shift) => default(TNumericOperations).RightShift(value, shift); 322 | 323 | /// 324 | /// Returns a value that indicates whether the values of two numeric objects are equal. 325 | /// 326 | /// The first value to compare. 327 | /// The second value to compare. 328 | /// true if the and parameters have the same value; otherwise, false. 329 | public static bool operator ==(Number left, Number right) => default(TNumericOperations).Equals(left, right); 330 | 331 | /// 332 | /// Returns a value that indicates whether two numeric objects have different values. 333 | /// 334 | /// The first value to compare. 335 | /// The second value to compare. 336 | /// true if and are not equal; otherwise, false. 337 | public static bool operator !=(Number left, Number right) => default(TNumericOperations).NotEquals(left, right); 338 | 339 | /// 340 | /// Returns a value that indicates whether a numeric value is less than another numeric value. 341 | /// 342 | /// The first value to compare. 343 | /// The second value to compare. 344 | /// true if is less than ; otherwise, false. 345 | public static bool operator <(Number left, Number right) => default(TNumericOperations).LessThan(left, right); 346 | 347 | /// 348 | /// Returns a value that indicates whether a numeric value is greater than another numeric value. 349 | /// 350 | /// The first value to compare. 351 | /// The second value to compare. 352 | /// true if is greater than ; otherwise, false. 353 | public static bool operator >(Number left, Number right) => default(TNumericOperations).GreaterThan(left, right); 354 | 355 | /// 356 | /// Returns a value that indicates whether a numeric value is less than or equal to another numeric value. 357 | /// 358 | /// The first value to compare. 359 | /// The second value to compare. 360 | /// true if is less than or equal to ; otherwise, false. 361 | public static bool operator <=(Number left, Number right) => default(TNumericOperations).LessThanOrEqual(left, right); 362 | 363 | /// 364 | /// Returns a value that indicates whether a numeric value is greater than or equal to another numeric value. 365 | /// 366 | /// The first value to compare. 367 | /// The second value to compare. 368 | /// true if is greater than ; otherwise, false. 369 | public static bool operator >=(Number left, Number right) => default(TNumericOperations).GreaterThanOrEqual(left, right); 370 | 371 | /// 372 | /// Defines an explicit conversion of an to a value. 373 | /// 374 | /// The value to convert to a . 375 | /// An object that contains the value of the parameter. 376 | /// is greater than 's MaxValue or less than 's MinValue. 377 | public static explicit operator Number(byte value) => default(TNumericOperations).Convert(value); 378 | 379 | /// 380 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 381 | /// 382 | /// The value to convert to a . 383 | /// An object that contains the value of the parameter. 384 | /// is greater than 's MaxValue or less than 's MinValue. 385 | [CLSCompliant(false)] 386 | public static explicit operator Number(sbyte value) => default(TNumericOperations).Convert(value); 387 | 388 | /// 389 | /// Defines an explicit conversion of an to a value. 390 | /// 391 | /// The value to convert to a . 392 | /// An object that contains the value of the parameter. 393 | /// is greater than 's MaxValue or less than 's MinValue. 394 | public static explicit operator Number(short value) => default(TNumericOperations).Convert(value); 395 | 396 | /// 397 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 398 | /// 399 | /// The value to convert to a . 400 | /// An object that contains the value of the parameter. 401 | /// is greater than 's MaxValue or less than 's MinValue. 402 | [CLSCompliant(false)] 403 | public static explicit operator Number(ushort value) => default(TNumericOperations).Convert(value); 404 | 405 | /// 406 | /// Defines an explicit conversion of an to a value. 407 | /// 408 | /// The value to convert to a . 409 | /// An object that contains the value of the parameter. 410 | /// is greater than 's MaxValue or less than 's MinValue. 411 | public static explicit operator Number(int value) => default(TNumericOperations).Convert(value); 412 | 413 | /// 414 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 415 | /// 416 | /// The value to convert to a . 417 | /// An object that contains the value of the parameter. 418 | /// is greater than 's MaxValue or less than 's MinValue. 419 | [CLSCompliant(false)] 420 | public static explicit operator Number(uint value) => default(TNumericOperations).Convert(value); 421 | 422 | /// 423 | /// Defines an explicit conversion of an to a value. 424 | /// 425 | /// The value to convert to a . 426 | /// An object that contains the value of the parameter. 427 | /// is greater than 's MaxValue or less than 's MinValue. 428 | public static explicit operator Number(long value) => default(TNumericOperations).Convert(value); 429 | 430 | /// 431 | /// Defines an explicit conversion of an to a value. This API is not CLS-compliant. 432 | /// 433 | /// The value to convert to a . 434 | /// An object that contains the value of the parameter. 435 | /// is greater than 's MaxValue or less than 's MinValue. 436 | [CLSCompliant(false)] 437 | public static explicit operator Number(ulong value) => default(TNumericOperations).Convert(value); 438 | 439 | /// 440 | /// Defines an explicit conversion of a value to a value. 441 | /// 442 | /// The value to convert to a . 443 | /// An object that contains the value of the parameter. 444 | /// is greater than 's MaxValue or less than 's MinValue. 445 | public static explicit operator Number(float value) => default(TNumericOperations).Convert(value); 446 | 447 | /// 448 | /// Defines an explicit conversion of a value to a value. 449 | /// 450 | /// The value to convert to a . 451 | /// An object that contains the value of the parameter. 452 | /// is greater than 's MaxValue or less than 's MinValue. 453 | public static explicit operator Number(double value) => default(TNumericOperations).Convert(value); 454 | 455 | /// 456 | /// Defines an explicit conversion of a value to a value. 457 | /// 458 | /// The value to convert to a . 459 | /// An object that contains the value of the parameter. 460 | /// is greater than 's MaxValue or less than 's MinValue. 461 | public static explicit operator Number(decimal value) => default(TNumericOperations).Convert(value); 462 | 463 | /// 464 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 465 | /// 466 | /// The value to convert to an . 467 | /// An object that contains the value of the parameter. 468 | /// is greater than 's MaxValue or less than 's MinValue. 469 | [CLSCompliant(false)] 470 | public static explicit operator sbyte(Number value) => default(TNumericOperations).ToSByte(value); 471 | 472 | /// 473 | /// Defines an explicit conversion of a object to an value. 474 | /// 475 | /// The value to convert to an . 476 | /// An object that contains the value of the parameter. 477 | /// is greater than 's MaxValue or less than 's MinValue. 478 | public static explicit operator byte(Number value) => default(TNumericOperations).ToByte(value); 479 | 480 | /// 481 | /// Defines an explicit conversion of a object to an value. 482 | /// 483 | /// The value to convert to an . 484 | /// An object that contains the value of the parameter. 485 | /// is greater than 's MaxValue or less than 's MinValue. 486 | public static explicit operator short(Number value) => default(TNumericOperations).ToInt16(value); 487 | 488 | /// 489 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 490 | /// 491 | /// The value to convert to an . 492 | /// An object that contains the value of the parameter. 493 | /// is greater than 's MaxValue or less than 's MinValue. 494 | [CLSCompliant(false)] 495 | public static explicit operator ushort(Number value) => default(TNumericOperations).ToUInt16(value); 496 | 497 | /// 498 | /// Defines an explicit conversion of a object to an value. 499 | /// 500 | /// The value to convert to an . 501 | /// An object that contains the value of the parameter. 502 | /// is greater than 's MaxValue or less than 's MinValue. 503 | public static explicit operator int(Number value) => default(TNumericOperations).ToInt32(value); 504 | 505 | /// 506 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 507 | /// 508 | /// The value to convert to an . 509 | /// An object that contains the value of the parameter. 510 | /// is greater than 's MaxValue or less than 's MinValue. 511 | [CLSCompliant(false)] 512 | public static explicit operator uint(Number value) => default(TNumericOperations).ToUInt32(value); 513 | 514 | /// 515 | /// Defines an explicit conversion of a object to an value. 516 | /// 517 | /// The value to convert to an . 518 | /// An object that contains the value of the parameter. 519 | /// is greater than 's MaxValue or less than 's MinValue. 520 | public static explicit operator long(Number value) => default(TNumericOperations).ToInt64(value); 521 | 522 | /// 523 | /// Defines an explicit conversion of a object to an value. This API is not CLS-compliant. 524 | /// 525 | /// The value to convert to an . 526 | /// An object that contains the value of the parameter. 527 | /// is greater than 's MaxValue or less than 's MinValue. 528 | [CLSCompliant(false)] 529 | public static explicit operator ulong(Number value) => default(TNumericOperations).ToUInt64(value); 530 | 531 | /// 532 | /// Defines an explicit conversion of a object to an value. 533 | /// 534 | /// The value to convert to an . 535 | /// An object that contains the value of the parameter. 536 | /// is greater than 's MaxValue or less than 's MinValue. 537 | public static explicit operator float(Number value) => default(TNumericOperations).ToSingle(value); 538 | 539 | /// 540 | /// Defines an explicit conversion of a object to an value. 541 | /// 542 | /// The value to convert to an . 543 | /// An object that contains the value of the parameter. 544 | /// is greater than 's MaxValue or less than 's MinValue. 545 | public static explicit operator double(Number value) => default(TNumericOperations).ToDouble(value); 546 | 547 | /// 548 | /// Defines an explicit conversion of a object to an value. 549 | /// 550 | /// The value to convert to an . 551 | /// An object that contains the value of the parameter. 552 | /// is greater than 's MaxValue or less than 's MinValue. 553 | public static explicit operator decimal(Number value) => default(TNumericOperations).ToDecimal(value); 554 | 555 | /// 556 | /// Defines an explicit conversion of a to a value. 557 | /// 558 | /// The value to convert to a . 559 | /// An object that contains the value of the parameter. 560 | /// is greater than 's MaxValue or less than 's MinValue. 561 | public static explicit operator Number(BigInteger value) => default(TNumericOperations).Convert(value); 562 | 563 | /// 564 | /// Defines an explicit conversion of a object to a value. 565 | /// 566 | /// The value to convert to a . 567 | /// An object that contains the value of the parameter. 568 | public static explicit operator BigInteger(Number value) => default(TNumericOperations).ToBigInteger(value); 569 | 570 | /// 571 | /// Defines an explicit conversion of a to a value. 572 | /// 573 | /// The value to convert to a . 574 | /// An object that contains the value of the parameter. 575 | /// The type argument is not supported. 576 | /// is greater than 's MaxValue or less than 's MinValue. 577 | public static explicit operator Number(nint value) => default(TNumericOperations).Convert(value); 578 | 579 | /// 580 | /// Defines an explicit conversion of a object to an value. 581 | /// 582 | /// The value to convert to an . 583 | /// An object that contains the value of the parameter. 584 | /// The type argument is not supported. 585 | public static explicit operator nint(Number value) => Number.GetOperationsInternal().Convert(value.Value); 586 | 587 | /// 588 | /// Defines an explicit conversion of a to a value. 589 | /// 590 | /// The value to convert to a . 591 | /// An object that contains the value of the parameter. 592 | /// The type argument is not supported. 593 | /// is greater than 's MaxValue or less than 's MinValue. 594 | [CLSCompliant(false)] 595 | public static explicit operator Number(nuint value) => default(TNumericOperations).Convert(value); 596 | 597 | /// 598 | /// Defines an explicit conversion of a object to an value. 599 | /// 600 | /// The value to convert to an . 601 | /// An object that contains the value of the parameter. 602 | /// The type argument is not supported. 603 | [CLSCompliant(false)] 604 | public static explicit operator nuint(Number value) => Number.GetOperationsInternal().Convert(value.Value); 605 | } 606 | } -------------------------------------------------------------------------------- /src/Genumerics/NumericOperationsProvider.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Diagnostics; 28 | using System.Reflection; 29 | 30 | namespace Genumerics 31 | { 32 | /// 33 | /// The numeric operations provider base class. 34 | /// 35 | public abstract class NumericOperationsProvider 36 | { 37 | /// 38 | /// Gets the numeric operations type that handles the numeric type or else returns null. 39 | /// 40 | /// The numeric type. 41 | /// 42 | public abstract Type? GetOperationsType(); 43 | } 44 | 45 | internal sealed class DefaultNumericOperationsProvider : NumericOperationsProvider 46 | { 47 | public override Type? GetOperationsType() => default(DefaultNumericOperations) is INumericOperations ? typeof(DefaultNumericOperations) : null; 48 | } 49 | 50 | internal sealed class NullableNumericOperationsProvider : NumericOperationsProvider 51 | { 52 | public override Type? GetOperationsType() 53 | { 54 | var numericType = typeof(T); 55 | if (default(T) == null && numericType.IsValueType) 56 | { 57 | var underlyingType = numericType.GetGenericArguments()[0]; 58 | var underlyingOperations = typeof(Number) 59 | .GetMethod(nameof(Number.GetOperationsInternal), BindingFlags.Static | BindingFlags.NonPublic)! 60 | .MakeGenericMethod(underlyingType).Invoke(null, null)!; 61 | Debug.Assert(underlyingOperations.GetType().Name == "NumericOperationsWrapper`2"); 62 | var underlyingOperationsType = underlyingOperations.GetType().GetGenericArguments()[1]; 63 | return typeof(NullableNumericOperations<,>).MakeGenericType(underlyingType, underlyingOperationsType); 64 | } 65 | return null; 66 | } 67 | } 68 | 69 | internal sealed class FuncNumericOperationsProvider : NumericOperationsProvider 70 | { 71 | private readonly Func _operationsProvider; 72 | 73 | public FuncNumericOperationsProvider(Func operationsProvider) 74 | { 75 | _operationsProvider = operationsProvider; 76 | } 77 | 78 | public override Type? GetOperationsType() => _operationsProvider(typeof(T)); 79 | } 80 | } -------------------------------------------------------------------------------- /src/Genumerics/NumericOperationsWrapper.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Globalization; 28 | using System.Numerics; 29 | 30 | namespace Genumerics 31 | { 32 | // A class wrapper instead of using struct directly for better performance when used as an interface 33 | internal sealed class NumericOperationsWrapper : INumericOperations 34 | where TNumericOperations : struct, INumericOperations 35 | { 36 | public T Zero => default(TNumericOperations).Zero; 37 | 38 | public T One => default(TNumericOperations).One; 39 | 40 | public T MinusOne => default(TNumericOperations).MinusOne; 41 | 42 | public T MaxValue => default(TNumericOperations).MaxValue; 43 | 44 | public T MinValue => default(TNumericOperations).MinValue; 45 | 46 | public TypeCode TypeCode => default(TNumericOperations).TypeCode; 47 | 48 | public T Abs(T value) => default(TNumericOperations).Abs(value); 49 | 50 | public T Add(T left, T right) => default(TNumericOperations).Add(left, right); 51 | 52 | public T BitwiseAnd(T left, T right) => default(TNumericOperations).BitwiseAnd(left, right); 53 | 54 | public T Ceiling(T value) => default(TNumericOperations).Ceiling(value); 55 | 56 | public T Clamp(T value, T min, T max) => default(TNumericOperations).Clamp(value, min, max); 57 | 58 | public int Compare(T left, T right) => default(TNumericOperations).Compare(left, right); 59 | 60 | public T Convert(TFrom value) => default(TNumericOperations).Convert(value); 61 | 62 | public T Divide(T dividend, T divisor) => default(TNumericOperations).Divide(dividend, divisor); 63 | 64 | public T DivRem(T dividend, T divisor, out T remainder) => default(TNumericOperations).DivRem(dividend, divisor, out remainder); 65 | 66 | public bool Equals(T left, T right) => default(TNumericOperations).Equals(left, right); 67 | 68 | public T Floor(T value) => default(TNumericOperations).Floor(value); 69 | 70 | public bool GreaterThan(T left, T right) => default(TNumericOperations).GreaterThan(left, right); 71 | 72 | public bool GreaterThanOrEqual(T left, T right) => default(TNumericOperations).GreaterThanOrEqual(left, right); 73 | 74 | public bool IsEven(T value) => default(TNumericOperations).IsEven(value); 75 | 76 | public bool IsOdd(T value) => default(TNumericOperations).IsOdd(value); 77 | 78 | public bool IsPowerOfTwo(T value) => default(TNumericOperations).IsPowerOfTwo(value); 79 | 80 | public T LeftShift(T value, int shift) => default(TNumericOperations).LeftShift(value, shift); 81 | 82 | public bool LessThan(T left, T right) => default(TNumericOperations).LessThan(left, right); 83 | 84 | public bool LessThanOrEqual(T left, T right) => default(TNumericOperations).LessThanOrEqual(left, right); 85 | 86 | public T Max(T left, T right) => default(TNumericOperations).Max(left, right); 87 | 88 | public T Min(T left, T right) => default(TNumericOperations).Min(left, right); 89 | 90 | public T Multiply(T left, T right) => default(TNumericOperations).Multiply(left, right); 91 | 92 | public T Negate(T value) => default(TNumericOperations).Negate(value); 93 | 94 | public T OnesComplement(T value) => default(TNumericOperations).OnesComplement(value); 95 | 96 | public bool NotEquals(T left, T right) => default(TNumericOperations).NotEquals(left, right); 97 | 98 | public T BitwiseOr(T left, T right) => default(TNumericOperations).BitwiseOr(left, right); 99 | 100 | public T Parse(string value, NumberStyles? style, IFormatProvider? provider) => default(TNumericOperations).Parse(value, style, provider); 101 | 102 | public T Remainder(T dividend, T divisor) => default(TNumericOperations).Remainder(dividend, divisor); 103 | 104 | public T RightShift(T value, int shift) => default(TNumericOperations).RightShift(value, shift); 105 | 106 | public T Round(T value, int digits, MidpointRounding mode) => default(TNumericOperations).Round(value, digits, mode); 107 | 108 | public int Sign(T value) => default(TNumericOperations).Sign(value); 109 | 110 | public T Subtract(T left, T right) => default(TNumericOperations).Subtract(left, right); 111 | 112 | public BigInteger ToBigInteger(T value) => default(TNumericOperations).ToBigInteger(value); 113 | 114 | public byte ToByte(T value) => default(TNumericOperations).ToByte(value); 115 | 116 | public decimal ToDecimal(T value) => default(TNumericOperations).ToDecimal(value); 117 | 118 | public double ToDouble(T value) => default(TNumericOperations).ToDouble(value); 119 | 120 | public short ToInt16(T value) => default(TNumericOperations).ToInt16(value); 121 | 122 | public int ToInt32(T value) => default(TNumericOperations).ToInt32(value); 123 | 124 | public long ToInt64(T value) => default(TNumericOperations).ToInt64(value); 125 | 126 | public sbyte ToSByte(T value) => default(TNumericOperations).ToSByte(value); 127 | 128 | public float ToSingle(T value) => default(TNumericOperations).ToSingle(value); 129 | 130 | public string? ToString(T value, string? format, IFormatProvider? provider) => default(TNumericOperations).ToString(value, format, provider); 131 | 132 | public ushort ToUInt16(T value) => default(TNumericOperations).ToUInt16(value); 133 | 134 | public uint ToUInt32(T value) => default(TNumericOperations).ToUInt32(value); 135 | 136 | public ulong ToUInt64(T value) => default(TNumericOperations).ToUInt64(value); 137 | 138 | public T Truncate(T value) => default(TNumericOperations).Truncate(value); 139 | 140 | public bool TryParse(string? value, NumberStyles? style, IFormatProvider? provider, out T result) => default(TNumericOperations).TryParse(value, style, provider, out result); 141 | 142 | public T Xor(T left, T right) => default(TNumericOperations).Xor(left, right); 143 | 144 | #if SPAN 145 | public T Parse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider) => default(TNumericOperations).Parse(value, style, provider); 146 | 147 | public bool TryParse(ReadOnlySpan value, NumberStyles? style, IFormatProvider? provider, out T result) => default(TNumericOperations).TryParse(value, style, provider, out result); 148 | 149 | public bool TryFormat(T value, Span destination, out int charsWritten, ReadOnlySpan format = default, IFormatProvider? provider = null) => default(TNumericOperations).TryFormat(value, destination, out charsWritten, format, provider); 150 | #endif 151 | } 152 | } -------------------------------------------------------------------------------- /src/Genumerics/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region License 2 | // Copyright (c) 2019 Tyler Brinkley 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files (the "Software"), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | // OTHER DEALINGS IN THE SOFTWARE. 24 | #endregion 25 | 26 | using System; 27 | using System.Runtime.InteropServices; 28 | using System.Security; 29 | 30 | // Setting ComVisible to false makes the types in this assembly not visible 31 | // to COM components. If you need to access a type in this assembly from 32 | // COM, set the ComVisible attribute to true on that type. 33 | [assembly: ComVisible(false)] 34 | 35 | // The following GUID is for the ID of the typelib if this project is exposed to COM 36 | [assembly: Guid("719c7d93-e56c-492b-95a9-6914655b5cd5")] 37 | 38 | [assembly: AllowPartiallyTrustedCallers] 39 | 40 | [assembly: CLSCompliant(true)] -------------------------------------------------------------------------------- /src/Genumerics/genumerics.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TylerBrinkley/Genumerics/4d205f0d3a6978d95ec3047154b7b96799883269/src/Genumerics/genumerics.snk --------------------------------------------------------------------------------