10

I have two questions regarding .NET's decimal data type determinism:

  1. Are decimal type computations cross-platform deterministic? Or in other words, will math operations on decimal type produce exactly the same results on all platforms?

  2. Is casting decimal number to float or double cross-platform deterministic (casts will always produce exactly the same result)?

phuclv
  • 37,963
  • 15
  • 156
  • 475
zigzag
  • 579
  • 5
  • 17
  • 8
    I wouldn't be at all surprised to see some differences in corner cases between Mono and the Microsoft implementations... – Jon Skeet Sep 06 '16 at 09:15
  • 2
    Indeed, [there was a bug in the Mono implementation](http://stackoverflow.com/questions/26414708/precision-of-c-sharp-decimal-type-division-is-different-on-mono) that caused different results compared to the Windows one. I would expect others. – Matthew Watson Sep 06 '16 at 09:21
  • As far as I know, the answers to both questions could be yes. No guarantee. However, there is an issue with conversion to `double` in relation to trailing zeroes of the `decimal`. It is possible to have two `decimal` values that only differ by the number of trailing zeroes, and therefore these two `decimal`s are considered equal (even if they have distinct internal representations), such that when you convert them to `double`, the resulting `double` values are distinct. _Addition:_ This also proves that the conversion to `double` does not always pick the nearest destination. Want example? – Jeppe Stig Nielsen Sep 06 '16 at 09:21
  • It would indeed be good to see an example: that doesn't sound right to me. – Bathsheba Sep 06 '16 at 09:26
  • 1
    @Bathsheba An example: `var a = ((double)200.000000000000000000000M).ToString("R"); var b = ((double)200.0000000000000000000000M).ToString("R"); var c = ((double)200.00000000000000000000000M).ToString("R");`. Taken from [late answer here](http://stackoverflow.com/a/23638323/1336654). Because the `System.Decimal` implementation of `GetHashCode()` works by first converting to `double` and then truncating that `double` a bit, the decimal involved in `a` here even has the wrong `decimal.GetHashCode()`. The other two have the right hash code. – Jeppe Stig Nielsen Sep 06 '16 at 09:33
  • Not what I was hoping for. So custom numeric data type is the only way to get cross-platform deterministic computations that have numbers with fractional part in .NET. Reinventing the wheel for all non-basic math operations that go with that custom data type is the tougher part I think. – zigzag Sep 06 '16 at 11:17
  • I guess, *apart from bugs*, decimals should be deterministic, since they are implemented in .NET, floats and doubles are probably not, because they are computed on the CPU (which is at best following an standard). Casts involve both and I wouldn't expect them to be deterministic. – Stefan Steinegger Jul 20 '20 at 06:05

1 Answers1

0

There's a lot of fear-mongering in the comments to this question.

First, there's the fear of a certain Mono bug sometime in the past. Not only has that been already fixed, but just don't use Mono in 2021. Both .Net Core and .Net5 are fully cross-platform.

Then there's the fear that GetHashCode can return equal values for non-equal decimal instances. Yes, that's how GetHashCode (and indeed, all hash functions) work, otherwise you could compress any arbitrary data type to 4 bytes. Instead of typing all that, I recommend reading a book on hashing.

To the OP, there's no need to either listen to those people or reinvent decimal. It's perfectly safe to use.

Blindy
  • 65,249
  • 10
  • 91
  • 131