3

I am trying to round a number to 7 decimal places but I noticed that Math.Round doesn't work correctly with some numbers:

Math.Round(39.248779999999996,3) => 39.249 Math.Round(39.248779999999996,4) => 39.2488 Math.Round(39.248779999999996,5) => 39.248779999999996 Math.Round(39.248779999999996,6) => 39.248779999999996 Math.Round(39.248779999999996,7) => 39.248779999999996 

Can anyone explain me this behaviour?

3
  • 7
    These are floating-point values. They don't have a finite binary representation with an arbitrary number of digits. Convert it to a decimal type if you want a precise representation. Commented Jun 25, 2016 at 13:48
  • The problem is I must pass a double to an external component for wich I cannot change it's method signature and that component will throw an error if the number has more than 7 decimal places. Is there a way to effectively round that double number to 7 decimal places? Commented Jun 26, 2016 at 12:29
  • Um, there is no way for a double to store a rounded value, so that wouldn't have worked anyway. The external component is buggy. Doubles do not have fixed numbers of decimal places. It should have used the decimal type. Commented Jun 26, 2016 at 12:32

1 Answer 1

7

If you need precision, use decimal and not double/float;

var num = 39.248779999999996; // num is double. var num = 39.248779999999996m; // num is decimal. 

The decimal keyword indicates a 128-bit data type. Compared to floating-point types, the decimal type has more precision and a smaller range, which makes it appropriate for financial and monetary calculations.

Edit:

You can't represent all numbers exactly in float/double:

Binary floating point arithmetic is fine so long as you know what's going on and don't expect values to be exactly the decimal ones you put in your program, and don't expect calculations involving binary floating point numbers to necessarily yield precise results. Even if two numbers are both exactly represented in the type you're using, the result of an operation involving those two numbers won't necessarily be exactly represented. This is most easily seen with division (eg 1/10 isn't exactly representable despite both 1 and 10 being exactly representable) but it can happen with any operation - even seemingly innocent ones such as addition and subtraction.

For Example:

double doubleValue = 1f / 10f; // => 0.10000000149011612 decimal decimalValue = 1m / 10m; // => 0.1 

You can truncate the digits to ensure max of 7 digits, but you can't exactly round the value:

double value = 39.248779999999996; double roundTo = Math.Pow(10, 7); double resultResult = Math.Truncate(value * roundTo) / roundTo; // result is : 39.2487799 
Sign up to request clarification or add additional context in comments.

3 Comments

The problem is I must pass a double to an external component for wich I cannot change it's method signature and that component will throw an error if the number has more than 7 decimal places. Is there a way to effectively round that double number to 7 decimal places?
I tried that and the result remains equal to 39.248779999999996. If you used Console.WriteLine to display the result make sure you used Console.WriteLine(result.ToString("r")); because by default the general ("G") format specifier is used (msdn.microsoft.com/en-us/library/dwhawy9k.aspx#RFormatString)
@smeegoan check the edits, i think this is your last hope using double.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.