3

C# supports infinity math for binary floating point types (Double and Single) (see: Express mathematical infinity in C#), but not for Decimal. I like the Decimal type for the precision it offers, but I need support for infinity math (details below) as well.

Is there a 'lazy' way to create an InfinityDecimal struct that adds support for -Inf/+Inf/NaN, much like the Nullable generic struct adds support for Nullable types? Perhaps there's some interesting use of attributes that might apply? An existing math library that includes such a beast?

Otherwise I should create a class or struct with a Decimal value property, and explicitly implement each of the public methods of the struct Decimal type, returning the results of the equivalent Decimal operation unless a operand is, or a result should be, +/-Inf or NaN. Right?

Infinity Math Operations:

+INF + N    = +INF (where –INF < N < INF)
-INF + N    = -INF (where –INF < N < INF)
+INF + +INF = +INF
-INF - +INF = -INF
+INF - +INF = NAN 
+INF * +INF = +INF
+INF * -INF = -INF
-INF * -INF = +INF
+INF / +INF = NAN
-INF / -INF = NAN
-INF / +INF = NAN
+INF / -INF = NAN
+INF / 0    = +INF
-INF / 0    = -INF
+INF / N    = +INF (where 0 < N < INF)
Community
  • 1
  • 1
Pauli Price
  • 4,187
  • 3
  • 34
  • 62
  • Are you suggesting this be added to the BCL or are you asking *how* to do it in C#? – Peter Ritchie Nov 27 '13 at 18:25
  • @PeterRitchie It's pretty clear OP is looking for the latter.. – Zong Nov 27 '13 at 18:27
  • 1
    "Otherwise I should create a class or struct with a Decimal value property, and explicitly implement each of the public methods of the struct Decimal type" Yes, you'll need to do that. It'll be tedious, but not particularly hard. – Servy Nov 27 '13 at 18:27
  • How to do it. Ideally, I'd prefer it be added to the BCL, but in the short term I'd like to see if I can get there by finding an existing implementation or through some reasonable shortcut. – Pauli Price Nov 27 '13 at 18:28
  • 1
    Define your own type that encapsulates a decimal value and an enum to indicate whether the value is infinity or the decimal value. FWIW, decimal is not about precision. It is about decimal representation. Decimal has finite precision, just like double. But decimal is, well, decimal, and double is binary. So perhaps you should reconsider why you think decimal is so good. – David Heffernan Nov 27 '13 at 18:49
  • @DavidHeffernan - Precision is perhaps the wrong term. Generally, for financial calculations, `Decimal` is preferred over `Double.` When evaluating financial performance one may encounter returns of +/- Infinity or NaN, but I don't think that then justifies using Double. – Pauli Price Nov 27 '13 at 20:03

1 Answers1

6

If you look at what Double and Single do, they basically reserve a value to represent positive and negative infinity. This value is basically as close to positive and negative infinity that is reasonably possible to represent in each type. This, by inference, is 1 divided by the smallest value that isn't zero (i.e. Epsilon). Of course, Decimal does not have an Epsilon property. You could create your own epsilon value by creating a value very close to being zero without being zero:

var DecimalEpsilon = new decimal(1,0,0,false,27);

Effectively 0.000000000000000000000000001m.

You could then create positive and negative infinity in the same way that Single and Double do:

var DecimalPositiveInfinity =  1m / DecimalEpislon;
var DecimalNegativeInfinity = -1m / DecimalEpislon;

Unfortunately, you'd have to deal with dealing with decimalValue/zeroValue yourself and wrap the DivideByZeroException yourself and return the appropriate infinity constant--which really means wrapping all divisions. Same likely goes for NaN, as that is also not a Decimal concept (which is modeled in Single/Double as PositiveInfinity/PositiveInfinity.

Decimal was added to model money and to have as much precision as possible to avoid rounding errors and loss of money :). In the concept of "money", infinity doesn't make much sense. :)

Implementing the rest of what you want is effectively comparisons...

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • I don't know that the concepts of infinity or not-a-number are any less meaningful with money than with anything else. Calculations whose results aren't representable will cause trouble whether they throw immediate exceptions or yield a "sentinel" value. There are many cases where it's nicer to have a batch of code which is guaranteed to run as a unit and check afterward whether something went wrong, than to deal with the possibility that a piece of code might throw an exception halfway through. Immediate exceptions may be easier to troubleshoot than deferred ones... – supercat May 27 '14 at 18:14
  • ...but having a `ThreadStatic` reference to a computation context which could enable/disable immediate error trapping or capture a stacktrace from the first out-of-bounds calculation would make it possible for a system to make both styles of error-handling available to code, depending upon its immediate needs. – supercat May 27 '14 at 18:16
  • I look forward to seeing details in your answer – Peter Ritchie May 28 '14 at 02:52
  • 2
    Instead of using 1/epsilon for infinity, I think it would make more sense to directly use decimal.MaxValue (which might be equal) but just seems a safer way to go. – Jeff Walker Code Ranger Dec 29 '15 at 00:31