Проверьте, является ли число с плавающей запятой целочисленным
Этот код работает (С# 3)
double d;
if(d == (double)(int)d) ...;
- Есть ли лучший способ сделать это?
- По посторонним причинам я хочу избежать двойного броска; какие хорошие способы существуют, кроме этого? (даже если они не так хороши)
Примечание. Несколько человек указали на (важную) точку, что == часто является проблематичным исправлением с плавающей запятой. В этом случае я ожидаю значения в диапазоне от 0 до нескольких сотен, и они должны быть целыми (не ints являются ошибками), поэтому, если эти точки "не должны" быть проблемой для меня.
Ответы
Ответ 1
d == Math.Floor(d)
делает то же самое другими словами.
NB: Надеюсь, вы осознаете, что вы должны быть очень осторожны при выполнении такого рода вещей; floats/doubles очень легко накапливают мелкие ошибки, которые делают точные сравнения (например, этот) неудачными без какой-либо очевидной причины.
Ответ 2
Если ваш двойник является результатом другого вычисления, вы, вероятно, захотите что-то вроде:
d == Math.Floor(d + 0.00001);
Таким образом, если бы была небольшая ошибка округления, она все равно будет соответствовать.
Ответ 3
Это сработает, я думаю:
if (d % 1 == 0) {
//...
}
Ответ 4
Я не могу ответить на конкретную часть вопроса, относящуюся к С#, но я должен указать, что вам, вероятно, не хватает общей проблемы с числами с плавающей запятой.
Как правило, целочисленность не определена на поплавках. По той же причине, что равенство не определено на поплавках. Расчеты с плавающей запятой обычно включают ошибки округления и представления.
Например, 1.1 + 0.6 != 1.7
.
Yup, это то, как работают числа с плавающей запятой.
Здесь 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16
.
Строго говоря, самое близкое к сопоставлению равенства, которое вы можете делать с поплавками, сравнивает их с выбранной точностью.
Если этого недостаточно, вы должны работать с представлением десятичного числа с представлением числа с плавающей запятой со встроенным диапазоном ошибок или с символическими вычислениями.
Ответ 5
Вам не нужен дополнительный (двойной). Это работает:
if (d == (int)d) {
//...
}
Ответ 6
Использовать Math.Truncate()
Ответ 7
Если вы просто собираетесь его преобразовать, ответ Майка Ф/Хота хороший, но не совсем ответит на ваш вопрос. Если вы собираетесь фактически протестировать, и это действительно важно, я рекомендую вам внедрить что-то, что включает погрешность.
Например, если вы рассматриваете деньги и хотите проверить даже долларовые суммы, вы можете сказать (следуя схеме Хота):
если (Math.abs(d - Math.Floor(d + 0,001)) < 0,001)
Другими словами, возьмите абсолютное значение разности значения и целочисленного представления и убедитесь, что оно мало.
Ответ 8
Простой тест, такой как "x == floor (x)", математически гарантирован для правильной работы для любого номера FP с фиксированной точностью.
Все законные FP-кодировки с фиксированной точностью представляют собой различные действительные числа, поэтому для каждого целого x существует не более одной FP-кодировки с фиксированной точностью, которая точно соответствует ей.
Следовательно, для любого целого x, который МОЖЕТ быть представлен таким образом, мы имеем x == floor (x) обязательно, так как floor (x) по определению возвращает наибольшее число FP y такое, что y <= x и y представляет собой целое число; поэтому floor (x) должен возвращать x.
Ответ 9
Это позволит вам выбрать, какую точность вы ищете, плюс или минус половину галочки, для учета дрейфа с плавающей запятой. Сравнение также является целым.
static void Main(string[] args)
{
const int precision = 10000;
foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
{
if ((int) (d*precision + .5)%precision == 0)
{
Console.WriteLine("{0} is an int", d);
}
}
}
а выход -
2 is an int
1.99999999 is an int
2.00000001 is an int
Ответ 10
Что-то вроде этого
double d = 4.0;
int i = 4;
bool equal = d.CompareTo(i) == 0; // true
Ответ 11
Не могли бы вы использовать этот
bool IsInt(double x)
{
try
{
int y = Int16.Parse(x.ToString());
return true;
}
catch
{
return false;
}
}
Ответ 12
Для обработки точности двойного...
Math.Abs(d - Math.Floor(d)) <= double.Epsilon
Рассмотрим следующий случай, когда значение меньше, чем double.Epsilon не сравнивается как ноль.
// number of possible rounds
const int rounds = 1;
// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;
// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));
// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);
// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));