2

Sorry for asking such a beginner question but I can't figure this out.

I have a long integer that I'd like to divide by 1.28 then round it up or down to the nearest integer.

long size = 24524343254;
double ratio = 1.28;
size = size * 1.28; //Error Cannot implicitly convert type 'double' to 'long'
John Saunders
  • 160,644
  • 26
  • 247
  • 397
Andre Walker
  • 79
  • 1
  • 1
  • 11

3 Answers3

6

You need to explicitly cast the double result back to long (as the compiler states - there is not implicit conversion):

size = (long)Math.Round(size * 1.28);

You need Math.Round if you want to round to nearest (there is a special case for when the number to round is halfway between two numbers, then it's rounded towards the nearest even by default). You can also simply cast the result back (long)(size * 1.28) if you only want to round towards 0.

As pointed out by @CodeInChaos the implicit cast from long to double (size * 1.28 will cast size into a double first) can result in the loss of precision as doubles only have a precision of 53 bits but long is 64bit.

ChrisWue
  • 18,612
  • 4
  • 58
  • 83
  • `Math.Round` uses Bankers' Rounding (rounds to nearest even) by default. – Cameron Mar 10 '12 at 22:28
  • 1
    @Cameron: This only applies mid point rounding (`1.1` is still rounded to `1` and not `2`) – ChrisWue Mar 10 '12 at 22:32
  • 2
    It's important to note, that the implicit cast from `long` to `double` is lossy. `double` has 53 mantissa bits, whereas `long` has 63. – CodesInChaos Mar 10 '12 at 22:33
  • @ChrisWue: Yes; my comment is misleading! Still, it's important to be aware of. – Cameron Mar 10 '12 at 22:35
  • @Cameron: Yeah, there are many hidden traps when dealing with conversion between floating point and int. Almost surprising that in 99.9% of all cases the result is what you expect - unfortunately the other 0.1% are the bugs in your application. – ChrisWue Mar 10 '12 at 22:45
2

You should cast result as long.

size = (long)Math.Round(size * 1.28);
Onur
  • 599
  • 4
  • 12
2

You could also consider using decimal.

size = (long)Math.Round(size * 1.28m);//note the m making the literal a decimal.

This offers two advantages over double in this situation:

  • decimal can represent every long value exactly (Unlike double which only has 53 mantissa bits, decimal has >90 mantissa bit, with is enough to represent the 63 bits used by long)
  • it can represent 1.28 exactly.

You should also make sure, that MidpointRounding.ToEven is fine for you. It rounds 1.5 to 2, but 0.5 to 0.

When using Decimal casting to long if the value is outside the range of long will cause an exception.

When using double overflow behavior depends on the mode. If you're in a checked section, it will throw an exception, in an unchecked context it will result in an undefined value. Since undefined values are rarely desirable, I recommend using checked with double:

size = checked((long)Math.Round(size * 1.28));
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262