Проверьте, является ли double целочисленным [дубликат]

Что вы можете сделать по этому поводу?

Здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. Но очень мало о том, как предотвратить проблему или, по крайней мере, сделать ее легче поймать.

Проверить аргументы

Например, методы могут проверять разные аргументы, чтобы увидеть, null и выбросить ArgumentNullException, исключение, явно созданное для этой конкретной цели.

Конструктор для ArgumentNullException даже принимает имя параметра и сообщение как аргументы, чтобы вы могли точно сказать разработчику, что проблема.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Использовать инструменты

Есть также несколько библиотек, которые могут помочь. Например, «Resharper» может предоставить вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute

В разделе «Контракты кода Microsoft» вы используете синтаксис, например Contract.Requires(obj != null), который дает вам проверку выполнения и компиляцию: Представление кодовых контрактов .

Существует также «PostSharp», который позволит вам просто использовать такие атрибуты:

public void DoSometing([NotNull] obj)

Сделав это и сделав PostSharp частью вашего процесса сборки, obj будет проверяться на нуль во время выполнения. См. Ошибка проверки PostSharp

Решение для простого кода

Или вы всегда можете использовать свой собственный подход, используя простой старый код. Например, вот структура, которую вы можете использовать, чтобы поймать нулевые ссылки. Он моделируется после той же концепции, что и Nullable:

[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull(T value)
    {
        return new NotNull { Value = value };
    }
}

. Вы использовали бы очень похоже на то, как вы бы использовали Nullable, за исключением того, что цель заключалась в том, чтобы сделать абсолютно противоположное - не разрешать null. Вот несколько примеров:

NotNull person = null; // throws exception
NotNull person = new Person(); // OK
NotNull person = GetPerson(); // throws exception if GetPerson() returns null

NotNull неявно отбрасывается в и из T, поэтому вы можете использовать его в любом месте, где это необходимо. Например, вы можете передать объект Person методу, который принимает значение NotNull:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull person)
{
    Console.WriteLine(person.Value.Name);
}

Как вы можете видеть выше, как с помощью nullable, вы получите доступ к базовому значению через Value имущество. Кроме того, вы можете использовать явный или неявный листинг, вы можете увидеть пример с возвращаемым значением ниже:

Person person = GetPerson();

public static NotNull GetPerson()
{
    return new Person { Name = "John" };
}

Или вы даже можете использовать его, когда метод просто возвращает T (в этом случае Person), выполнив бросок. Например, следующий код будет похож на код выше:

Person person = (NotNull)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

Объединить с Extension

Объединить NotNull с методом расширения, и вы можете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:

[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
    public static T NotNull(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("null value not allowed");
        }

        return @this;
    }
}

И вот пример того, как он может быть использован:

var person = GetPerson().NotNull();

GitHub

Для вашей справки я сделал код выше, доступный на GitHub, вы можете найти его по адресу:

https://github.com/luisperezphd/NotNull

Функция родственного языка

В C # 6.0 был введен «оператор с нулевым условием», который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты, и если какой-либо из них null, все выражение возвращает null.

Это уменьшает количество нулевых проверок, которые вы должны выполнять в некоторых случаях. Синтаксис заключается в том, чтобы поставить вопросительный знак перед каждой точкой. Возьмите следующий код, например:

var address = country?.State?.County?.City;

Представьте, что country является объектом типа Country, который имеет свойство, называемое State и т. Д. Если country, State, County или City - null, то address will be null . Therefore you only have to check whether адрес is null`.

Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.

Встроенный как Nullable?

C # имеет красивую стенографию для Nullable, вы можете сделать что-то нулевое помещая знак вопроса после такого типа int?.

Было бы неплохо, если бы у C # было что-то вроде структуры NotNull выше и имела аналогичную стенографию, может быть, восклицательный знак (!), чтобы вы могли написать что-то вроде: public void WriteName(Person! person).

34
задан Jacob 5 October 2009 в 19:33
поделиться

13 ответов

Используйте std::modf :

double intpart;
modf(value, &intpart) == 0.0

Не конвертируйте в int! Число 1.0e+300 также является целым числом.

Редактирование: как указывает Пит Киркхам, передавая 0, поскольку второй аргумент не гарантируется стандартом для работы, требуя использования фиктивной переменной и , к сожалению, делает код намного менее изящным.

65
ответ дан Alec Jacobson 4 September 2018 в 09:38
поделиться
  • 1
    Я понятия не имел modf до сих пор. – GManNickG 5 October 2009 в 19:35
  • 2
    Согласовано. +1 для самородков в стандартной библиотеке C. Хотя я использовал бы NULL вместо 0, но я понимаю, что это довольно спорная проблема на C ++, без уважительной причины. – Chris Lutz 5 October 2009 в 19:44
  • 3
    Фактически, передача 0 в качестве второго аргумента не только не гарантируется, но и будет работать на многих платформах. – Stephen Canon 6 October 2009 в 04:59
  • 4
    Я думаю, вам лучше сравнить возвращаемое значение modf на epsilon, а не на ноль – qrdl 6 October 2009 в 08:51
  • 5
    Любая смутно грамотная реализация modf на хосте с арифметикой IEEE-754 будет always производить точную дробную часть. Если ваша платформа не имеет достаточно грамотной реализации математической библиотеки, вы должны либо придерживаться целого числа, либо (лучше) находить новую платформу. – Stephen Canon 6 October 2009 в 13:43

Как насчет этого?

if ((d1 - (int)d1) == 0)
    // integer
2
ответ дан Ashwin 4 September 2018 в 09:38
поделиться

Я столкнулся с подобными вопросами. Поскольку мне все равно нужно было обойти двойник, вот что я нахожу:

double d = 2.000000001;
int i = std::round(d);
std::fabs(d-i) < 10 * std::numeric_limits<double>::epsilon()
0
ответ дан Denis 4 September 2018 в 09:38
поделиться

Как насчет

if (abs(d1 - (round(d1))) < 0.000000001) {
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Исправлено использование работы с округлением для отражения ошибки Anna found

Альтернативные решения:

if ((d1 - floor(d1) < 0.000000001) || (d1 - floor(d1) > 0.9999999999)) {
   /* Better store floor value in a temp variable to speed up */
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Theres также еще один с занятием, вычитая 0,5 и принимая abs () этого и сравнивая с 0.499999999, но я полагаю, что это не будет основным улучшением производительности.

4
ответ дан DVK 4 September 2018 в 09:38
поделиться
  • 1
    Целые числа (по крайней мере, до определенного размера) представлены точно в любой реальной реализации чисел с плавающей запятой, о которых я могу думать, поэтому я не думаю, что есть необходимость беспокоиться о точности для этой конкретной проблемы. – Laurence Gonsalves 5 October 2009 в 19:26
  • 2
    Как насчет случая, когда d1 = 0.999999999999999? – Anna 5 October 2009 в 19:26
  • 3
    Единственная проблема заключается в том, что пол имеет неправильный путь для отрицательных чисел. вы должны использовать trunc () – Martin York 5 October 2009 в 19:35
  • 4
    @Jacob: вы не хотите использовать минимальное значение. Вам нужно значение, которое соответствует точности, необходимой для приложения. – Martin York 5 October 2009 в 19:38
  • 5
    Я должен извиниться. Я был зафиксирован на числах, которые были точно целыми числами, не близкими к целому, а round - лучший выбор для решения, которое вы предоставили. – Mark Ransom 6 October 2009 в 03:36

Ниже у вас есть код для тестирования d1 и d2, который очень прост. Единственное, что вам нужно проверить, - это значение переменной равно тому же значению, преобразованному в тип int. Если это не так, то это не целое число.

#include<iostream>
using namespace std;

int main()
{
    void checkType(double x);
    double d1 = 555;
    double d2 = 55.343;        
    checkType(d1);
    checkType(d2);
    system("Pause");
    return 0; 
}
void checkType(double x)
{
     if(x != (int)x)
     {
          cout<< x << " is not an integer "<< endl;
     }
     else 
     {
         cout << x << " is an integer " << endl;
     }
};
0
ответ дан Igor Oks 4 September 2018 в 09:38
поделиться
  • 1
    Пожалуйста, используйте форматирование кода SO. Если строка начинается с четырех пробелов, SO будет форматировать ее как код. – Chris Lutz 5 October 2009 в 20:42

Во многих вычислениях вы знаете, что ваши результаты с плавающей запятой будут иметь небольшую числовую ошибку, которая может возникнуть в результате ряда умножений.

Так что вы действительно можете найти, так это вопрос в том, что это число внутри скажем, 1е-5 целочисленного значения. В этом случае я думаю, что это работает лучше:

bool isInteger( double value )
{
    double flr = floor( value + 1e-5 );
    double diff = value - flr;
    return diff < 1e-5;
}
0
ответ дан Jeroen Dirks 4 September 2018 в 09:38
поделиться
#include <math.h>
#include <limits>

int main()
{
  double x, y, n;
  x = SOME_VAL;
  y = modf( x, &n ); // splits a floating-point value into fractional and integer parts
  if ( abs(y) < std::numeric_limits<double>::epsilon() )
  {
    // no floating part
  }
}
1
ответ дан Kirill V. Lyadvinsky 4 September 2018 в 09:38
поделиться
int iHaveNoFraction(double d){
    return d == trunc(d);
}

Теперь это не было бы C, если бы у него не было около 40 лет языковых версий ...

В C, == возвращает int, но в C ++ он возвращает bool. По крайней мере, на моем Linux-дистрибутиве (Ubuntu) вам нужно либо объявить double trunc(double);, либо вы можете скомпилировать с -std=c99 или объявить макрос уровня, чтобы получить <math.h>, чтобы объявить его.

3
ответ дан moffeltje 4 September 2018 в 09:38
поделиться
  • 1
    Может быть, сделать возвращаемый тип bool, так как это возвращает логическое значение? – Daniel Bingham 5 October 2009 в 19:31
  • 2
    trunc () лучше, чем floor (). Он работает для отрицательных чисел. – Martin York 5 October 2009 в 19:36
  • 3
    Alcon, хорошо, это может быть C ++. Конечно, в C это есть int. Я прояснил ситуацию ... – DigitalRoss 5 October 2009 в 19:42
  • 4
    В C ++ нет trunc (кроме ios::trunc). – avakar 5 October 2009 в 19:44
  • 5
    Это не совсем так, попробуйте, по крайней мере, с g ++ это работает. Хотя 14882 специально не объявляет trunc, он указывает, и я цитирую C ++ 26.5 (2), Содержимое этих заголовков совпадает с заголовками библиотеки стандартного C <math.h> и соответствующими реализациями , что должны иметь trunc(). Но да, может быть безопаснее использовать floor (). – DigitalRoss 5 October 2009 в 20:21

try:

bool isInteger(double d, double delta)
{
   double absd = abs(d);

   if( absd - floor(absd) > 0.5 )
      return (ceil(absd) - absd) < delta;

   return (d - floor(absd)) < delta;
}
0
ответ дан Patrice Bernassola 4 September 2018 в 09:38
поделиться

avakar был почти прав - используйте modf, но детали были отключены.

modf возвращает дробную часть, поэтому тест должен состоять в том, что результат modf равен 0.0.

modf принимает два аргумента, второй из которых должен быть указателем того же типа, что и первый аргумент. Передача NULL или 0 вызывает ошибку сегментации в среде выполнения g ++. В стандарте не указывается, что передача 0 безопасна; возможно, это работает на машине Авакара, но не делайте этого.

Вы также можете использовать fmod(a,b), который вычисляет a по модулю b, проходящий 1.0. Это также должно дать дробную часть.

#include<cmath>
#include<iostream>

int main ()
{
    double d1 = 555;
    double d2 = 55.343;

    double int_part1;
    double int_part2;

    using namespace std;

    cout << boolalpha;
    cout << d1 << " " << modf ( d1, &int_part1 ) << endl;
    cout << d1 << " " << ( modf ( d1, &int_part1 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;

    cout << d1 << " " << fmod ( d1, 1.0 ) << endl;
    cout << d1 << " " << ( fmod ( d1, 1.0 ) == 0 ) << endl;
    cout << d2 << " " << fmod ( d2, 1.0 ) << endl;
    cout << d2 << " " << ( fmod ( d2, 1.0 ) == 0 ) << endl;


    cout.flush();

    modf ( d1, 0 ); // segfault

}
4
ответ дан Pete Kirkham 4 September 2018 в 09:38
поделиться
  • 1
    +1, я проверил стандарт, и действительно, для этого требуется указатель на объект в качестве второго аргумента modf. Благодарю. – avakar 5 October 2009 в 20:35
  • 2
    О, и вам не нужно flush, передача endl делает это для вас. :-) – avakar 5 October 2009 в 20:40
  • 3
    +1 также вызывает ошибку шины на GCC на OS X. Если бы только стандарты были яснее! – Chris Lutz 5 October 2009 в 20:41

Предполагая, что среда, совместимая с c99 и IEEE-754,

(trunc(x) == x)

является другим решением и будет (на большинстве платформ) иметь немного лучшую производительность, чем modf, потому что ей нужно только произвести целое число часть.

Обратите внимание, что trunc дает результат с двойной точностью, поэтому вам не нужно беспокоиться о преобразованиях вне диапазона, как это было бы с (int)x.


Изменить: как указывает @pavon в комментарии, вам может потребоваться добавить еще одну проверку, в зависимости от того, заботитесь о бесконечности или нет, и какой результат вы хотите получить, если x бесконечен.

5
ответ дан Stephen Canon 4 September 2018 в 09:38
поделиться
  • 1
    Обратите внимание, что этот тест будет считать +/- бесконечность целыми числами. – pavon 18 July 2017 в 23:10
  • 2
    @pavon: почти разумно сказать, что бесконечность является четным целым числом в IEEE 754 (в том смысле, что все достаточно большие числа с плавающей запятой являются целыми числами, поэтому бесконечность «должна быть») , это вздор, но привлекательная глупость). – Stephen Canon 24 July 2017 в 14:52
  • 3
    Ну, все тесты на этой странице будут считать, что ± ∞ является целым числом. – K._ 8 March 2018 в 02:14
  • 4
    @ K._ Не требуется проверка для NaN (если вы не хотите рассматривать NaN как целое число), потому что NaN не равно самому себе. – Stephen Canon 8 March 2018 в 15:09
  • 5
    Да неужели? Прости; удалил это. Тогда я думаю, что этот метод будет лучшим среди этих ответов. – K._ 8 March 2018 в 15:14

Предполагая, что у вас есть библиотека cmath <math.h>, вы можете проверить число против floor . Если число может быть отрицательным, убедитесь, что вы сначала получаете absolute .

bool double_is_int(double trouble) {
   double absolute = abs( trouble );
   return absolute == floor(absolute);
}
9
ответ дан tj111 4 September 2018 в 09:38
поделиться
  • 1
    Для здравого смысла я рекомендую переосмыслить ваш выбор имени параметра. – Alan 5 October 2009 в 19:44
  • 2
    @ Алан, хорошо выглядящий. Изменено. – tj111 5 October 2009 в 19:49
  • 3
    Я думаю, что сначала не нужно сначала обращаться к абсолютной ценности. – updogliu 26 February 2012 в 05:31
  • 4
    Я слегка ухмыльнулся, когда увидел ваше выбранное имя для параметра. Спасибо, это сработало для меня. +1 – Charles 24 December 2015 в 01:35

Пример фрагмента кода, который делает это:

if (  ABS( ((int) d1) - (d1)) )< 0.000000001) 

 cout <<"Integer" << endl;

else

 cout <<"Flaot" << endl;

EDIT: Изменено, чтобы отобразить правильный код.

-1
ответ дан VNarasimhaM 4 September 2018 в 09:38
поделиться
  • 1
    Что насчет 100.01? – Calyth 5 October 2009 в 19:23
  • 2
    если # равно 1.0000000001 (как может быть возвращено, например, БД сервера), это не сработает. – DVK 5 October 2009 в 19:24
  • 3
    Это неверно , поскольку вы не можете использовать% на двойном d1 – Jacob 5 October 2009 в 19:24
Другие вопросы по тегам:

Похожие вопросы: