1

In Java and C#:

int a = (int)(-1.5 + 2.5);
int b = (int)(-1.55 + 2.55);
int c = (int)(1.45 + 2.55);
// a = 1; b = 0; c = 4;

Could anyone explain why adding positive number to negative one with 2 or more digits after decimal point causes decimal number break? "b = 0.99999999999999978".

So the question is - why "-1.5 + 2.5 = 1", but "-1.55 + 2.55 = 0"?

Maksim
  • 264
  • 7
  • 20
  • 7
    possible duplicate of [Why Are Floating Point Numbers Inaccurate?](http://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) – gvlasov Feb 20 '15 at 10:41

2 Answers2

4

It is because type double is an approximation.

Usually double denotes to IEEE 754 standart type decimal64


Math.Round allows you to specify a MidpointRounding:

ToEven - When a number is halfway between two others, it is rounded toward the nearest even number.

AwayFromZero - When a number is halfway between two others, it is rounded toward the nearest number that is away from zero.

Example:

var val = (int)Math.Round((-1.55 + 2.55), 1, MidpointRounding.ToEven);
Console.WriteLine(val);

Output : 1


Common bug for beginners is to write code like :

for (double i = 0.0; i == 6.0; i+=0.1)
{
    Console.WriteLine(i);
}

Hint: This will will not end in ~60 steps.

Margus
  • 19,694
  • 14
  • 55
  • 103
  • Also 0.99999999999999978 does not round to closest integer when you cast to int, but takes the Floor - it will become 0. – Margus Feb 20 '15 at 10:53
  • That's clear, but -1.5 is a double as well. Why it affects the only double numbers with 2+ digits after the point? – Maksim Feb 20 '15 at 10:56
  • @Maksim: That has nothing to do with the number of decimal digits. If you try `int d = (int)(-1.54 + 2.54)` the result will be again the expected one. As Johan Prins said in his answer: some decimals can't be represented exactly as floating point number. – Thomas Lielacher Feb 20 '15 at 11:01
  • Ok, so it's really important to check doubles before using them as integers and either use round function or BigDecimals. Thanks! – Maksim Feb 20 '15 at 11:05
1

Some decimals in the IEEE-754 format cannot be represented correctly when using double. Rather use BigDecimal. For example:

BigDecimal result = new BigDecimal("-1.55").add(new BigDecimal("2.55"));
Johan Prins
  • 112
  • 5
  • Is it possible to avoid converting double to String? – Maksim Feb 20 '15 at 10:54
  • It is recommended to use the String constructor on BigDecimal as the double constructor can also give incorrect results. Based on that I am going to go with "no". Try not to use double for these calculations in the first place. – Johan Prins Feb 20 '15 at 10:58