Страницы

Поиск по вопросам

четверг, 23 мая 2019 г.

C#. Как преобразовать число с плавающей точкой в аналогичное число, но только с заданным количеством знаков после запятой?

Доброго времени суток!
Возник следующий вопрос: к примеру, у нас есть переменная типа double и некоторая точность (переменная precition), которая будет определять количество интересующих нас знаков после запятой:
double x = 9.3813020199999; double precition = 0.001;
Зная вышеперечисленные данные, нам нужно получить точное число 9.381 (и без лишних нулей в конце). Есть ли способ это осуществить?
UPD Мне необходимо протестировать метод Sqrt (код ниже) и я не знаю, как правильно написать тест для NUnit, если метод возвращает число double. Ведь у нас должно быть expected-значение, которое сравнивается с возвращаемым значением метода.
public static double Sqrt(double x, int n, double precition) { if (x < 0 && n % 2 == 0) throw new ArgumentException();
double result = x / n; double previousResult; do { previousResult = result; result = ((double)1 / n) * ((n - 1) * previousResult + (x / Sqr(previousResult, n - 1))); } while (Math.Abs(result - previousResult) > precition);
return result; }
Пока мой тестирующий метод, написанный с помощью NUnit, выглядит так:
[TestFixture] public class NewtonSqrtTests { [TestCase(4, 2, 0.001, ExpectedResult = 2.000)] [TestCase(27, 3, 0.0001, ExpectedResult = 3.0000)] [TestCase(88, 2, 0.001, ExpectedResult = 9.380)] [TestCase(81, 2, 0.001, ExpectedResult = 9.000)] public double Sqrt_PositiveTest(double x, int n, double precition) { return NewtonSqrt.Sqrt(x, n, precition); } }


Ответ

Если говорить о десятичных знаках, то оставаться в рамках типа double бессмысленно: в нём вы не можете выразить вашу требуемую точность точно. Например, потому, что в типе double нельзя точно выразить ни число 0.001, ни число 9.381. (иллюстрация, связанный ответ)
Вам нужно перейти к типу decimal, который специально для этого предназначен.
double x = 9.3813020199999; decimal precision = 0.001m; decimal result = Math.Round((decimal)x / precision) * precision; // 9.381
Если количество десятичных знаков известно в виде числа, можно проще:
double x = 9.3813020199999; decimal result = Math.Round((decimal)x, 3); // 9.381

Обновление: Если оставаться в рамках типа double, вы не можете их сравнивать: равенство теоретически одинаковых чисел типа double, вычисленных разными путями — практически невероятное событие из-за ошибок округления. В таких случаях используется примерное равенство с точностью до epsilon. Например, в NUnit есть для таких целей специальные функции
Values of type float and double are normally compared using a tolerance specified by the Within modifier.

Комментариев нет:

Отправить комментарий