Подтвердить что ты не робот

Проверьте, является ли число с плавающей запятой целочисленным

Этот код работает (С# 3)

double d;
if(d == (double)(int)d) ...;
  • Есть ли лучший способ сделать это?
  • По посторонним причинам я хочу избежать двойного броска; какие хорошие способы существуют, кроме этого? (даже если они не так хороши)

Примечание. Несколько человек указали на (важную) точку, что == часто является проблематичным исправлением с плавающей запятой. В этом случае я ожидаю значения в диапазоне от 0 до нескольких сотен, и они должны быть целыми (не ints являются ошибками), поэтому, если эти точки "не должны" быть проблемой для меня.

4b9b3361

Ответ 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"));