4

Is it safe to cast an Integer to Double and back again?

To be a bit more specific, is it true for all integers that originalValue equals retrievedValue in the following scenario:

int originalValue = 42;
double backingField = (double)originalValue;
int retrievedValue = (int)backingField;

A bit of background/motivation: I am writing lots of micro services in C# with lots of interfaces. For a time interval in seconds, some clients send them as integers, others as floating values. I need to store them and return the same value as the client sent me. My question targets, if it is safe to assume, that when I retrieve an integer, but store all values as double that a cast to integer on the retrieving client will always return the original value. Especially as casting is done by truncating any values after the comma.

Can any cast to double result in a value lower than the integer, e.g. 42 -> 41.9999999999999?

vbreuss
  • 49
  • 1
  • 6
  • What kind of integer is it? – John Montgomery Oct 31 '18 at 20:03
  • My question is language independent. I am mostly working in c#, but am especially interested in the cases where the backingField is another language or a database. Assume that the integer is 32 bits long. – vbreuss Oct 31 '18 at 20:06
  • 1
    Doubles can precisely store all integer values [up to 2^53](https://stackoverflow.com/questions/1848700/biggest-integer-that-can-be-stored-in-a-double), so if it's only 32-bit that avoids that problem at least. I can't think of any other reason why it wouldn't be fine, but I'm not an expert on floating-point implementations so I'll let someone else answer. – John Montgomery Oct 31 '18 at 20:16
  • 2
    The `double` type might not be accurate in fractions, but it does not have an accuracy problem with integers. Any 10 base integer can be represented accurately as a binary number - but that is not the case when dealing with floating points - and that's the reason floating-point arithmetic sometimes returns rounded numbers. – Zohar Peled Nov 01 '18 at 06:40
  • It would probably be wise to go through floating point specification, but I did a quick test and tested all int values between `int.MinValue` and `int.MaxValue` and all were exactly the same after casting to `double` and back to `int` – FCin Nov 06 '18 at 13:30
  • @FCin, thanks for the effort! – vbreuss Nov 09 '18 at 19:05

2 Answers2

0

Simply casting just strips everything past the decimal point. I know you probably don't need to do any rounding, but just to make this answer more complete, here's the scoop on it. To round up or down, you can use the Math.Round() method. This will round up or down and provides a parameter on what to do if its midway. You could also use the Math.Floor() or Math.Ceiling() methods to implicitly round up or round down prior to casting. Here are some examples:

double num1 = 3.5;
double num2 = 3.2;
double num3 = 3.9;

(int)num1 // returns 3;
(int)num2 // returns 3;
(int)num3 // returns 3 also;
(int)Math.Round(num1) // returns 4
(int)Math.Round(num2) // returns 3
(int)Math.Round(num3) // returns 4
(int)Math.Floor(num1) // returns 3
(int)Math.Floor(num2) // returns 3
(int)Math.Floor(num3) // returns 3
(int)Math.Ceiling(num1) // returns 4
(int)Math.Ceiling(num2) // returns 4;
(int)Math.Ceiling(num3) // returns 4;
Icemanind
  • 47,519
  • 50
  • 171
  • 296
  • I know, that if I use rounding I won't have a problem at all. But the default casting from double to int just strips of everything after the comma and I can't guarantee how other clients that communicate with my service are doing their casting... – vbreuss Nov 09 '18 at 19:01
-5

There are predefined implicit conversions from int to long, float, double, or decimal. As put,

Any integral type is implicitly convertible to any floating-point type.

Check Implicit numeric conversions table (C# Reference) on ms docs.

Then, for the inverse operation

Precision but not magnitude might be lost in the conversions from int to float.

Float to double is an implicit cast also.

You might use a technique similar to testing frameworks asserting equality for numerical types with a tolerance.

To my detractors (edit)

Linked to your microservices issues, quoting Sam Newman on this

Be liberal in what you accept, conservative in what you send.

If you have a client requiring say, integers, store your data as double, or decimal, and use some mechanism to prevent loss of precision when casting to int, like Math.Floor or Math.Ceiling with proper rounding options. Else if another client requires some format for which there's an implicit cast with no loss of precision, you're off easy.

andrei.ciprian
  • 2,895
  • 1
  • 19
  • 29
  • 1
    All this says is that you can cast between these types without specifying a direct cast. It doesn't say anything about the effect of those casts. – LordWilmore Nov 06 '18 at 13:20