Почему оператор модуля не работает для double в С#?
Рассмотрим это:
double x,y;
x =120.0;
y = 0.05;
double z= x % y;
Я попробовал это и ожидал, что результат будет 0, но он вышел 0.04933333.
Однако
x =120.0;
y = 0.5;
double z= x % y;
действительно дал правильный результат 0.
Что здесь происходит?
Я пробовал Math.IEEERemainder(double, double)
, но он тоже не возвращал 0. Что здесь происходит?
Также, как в стороне, какой наиболее подходящий способ найти остаток в С#?
Ответы
Ответ 1
Из-за своего формата хранения double
не может хранить все значения точно так, как это было введено или отображено. Человеческое представление чисел обычно находится в десятичном формате, а double
основаны на двойной системе.
В double
, 120
хранится точно, потому что это целочисленное значение. Но 0.05
нет. Двойник приближается к ближайшему числу до 0.05
, которое он может представлять. 0.5
является степенью 2
(1/2
), поэтому его можно точно сохранить, и вы не получите ошибку округления.
Чтобы все номера точно совпадали с тем, как вы вводите/отображаете его в десятичной системе, используйте decimal
вместо этого.
decimal x, y;
x = 120.0M;
y = 0.05M;
decimal z = x % y; // z is 0
Ответ 2
Вы можете сделать что-то вроде:
double a, b, r;
a = 120;
b = .05;
r = a - Math.floor(a / b) * b;
Это должно помочь;)
Ответ 3
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems может помочь вам понять, почему вы получаете эти "странные" результаты. Там особая точность, которую могут иметь числа с плавающей запятой. Просто попробуйте эти запросы и посмотрите результаты:
0.5 в базе 2
0.05 в базе 2
Ответ 4
Я считаю, что если вы попытаетесь сделать то же самое с decimal
, он будет работать правильно.
Ответ 5
Модуль должен использоваться только с целым числом. Остальная часть исходит от евклидовой дивизии. С двойным результатом могут быть неожиданные результаты.
См. в этой статье
Ответ 6
Это то, что мы используем.. :)
public double ModuloOf(double v1, double v2)
{
var mult = 0;
//find number of decimals
while (v2 % 1 > 0)
{
mult++;
v2 = v2 * 10;
}
v1 = v1 * Math.Pow(10, mult);
var rem = v1 % v2;
return rem / Math.Pow(10, mult);
}