Является ли число типа Double целым

Тема в разделе "Общие вопросы по С и С++", создана пользователем Cadet, 15 янв 2011.

Статус темы:
Закрыта.
  1. Cadet

    Cadet Гость

    Нужно узнать, является ли число типа double целым:

    Методы сравнения дробной части с нулём типа
    Код (C++):
    if (t - floor(t) == 0){
    значит целое.
    }
    или
    Код (C++):
    if (t - int(t) == 0) {
    значит целое.
    }
    не работают.
    Также не работают методы:
    Код (C++):
    if (abs( d - (int)(d + 0.5) ) < 0.0001) {
    значит целое.
    }
    и
    Код (C++):
    if (d ==(int)d) {
    значит целое.
    }
    Как узнать!!??!!??!!??
     
  2. dreamer

    dreamer Гость

    Что-то мне подсказывает, что как минимум два первых метода должны работать, просто Вы берёте настолько большие числа, что на них не хватает точности типа, так что операция типа 12345000000000000.1 - 12345000000000000 даёт в результате ноль.

    Хотя вру... Второй метод не будет работать, ибо типа int не хватит.
     
  3. hosm

    hosm * so what *

    Регистрация:
    18 май 2009
    Сообщения:
    2.450
    Симпатии:
    7
    а что, на с++ нельзя взять дробную часть числа? и сравнить с точностью типа double (ибо с 0 сравнение может не подойти)
     
  4. dreamer

    dreamer Гость

    Можно. Именно это и сделал Cadet в первом же примере.

    Это как?
     
  5. Cadet

    Cadet Гость

    Эти методы (кроме предпоследнего) не работают, потому что иногда бывает такое: floor(5)=4 или int(3)=2. В этом можно убедиться, посмотрев результат выполнения следующего кода:
    Код (C++):
    double t=0;

    for (int i=0;i<100;i++)
    {
    t=t+0.1;
    cout << t <<" ___"<< floor(t);
    }
    Вот часть результата:
    17.7___17
    17.8___17
    17.9___17
    18___17
    18.1___18
    18.2___18
    18.3___18

    А предпоследний метод не работает потому что выражение abs( d - (int)(d + 0.5) ) при малом значении d иногда дает 0. У меня переменная d была равна 0.1. Получалось: abs( 0.1 - (int)(0.1 + 0.5) ) =0.
     
  6. dreamer

    dreamer Гость

    Проблема здесь не в отсечении дробной части, а в Вашем примере. При многократном сложении чисел с плавающей точкой появляется погрешность. Замените:
    Код (C++):
    t=t+0.1;
    на
    Код (C++):
    t=(double)i / 10;
    и функция floor будет отрабатывать как надо.
     
  7. hosm

    hosm * so what *

    Регистрация:
    18 май 2009
    Сообщения:
    2.450
    Симпатии:
    7
    я имела в виду нечто стандартное в какой-то либ языка. Гугль указан на modf, например.
     
  8. dreamer

    dreamer Гость

    Здесь, ИМХО, нет большой разницы, как именно искать дробную часть. Разве что modf, вероятно, будет работать быстрее, да и то не факт, ибо там по указателю целая часть возвращается. В приведённом Cadet примере modf также выдаёт ненулевую дробную часть на t=4, потому проблема этой функцией не решается.
     
  9. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    if ( ceil( t ) == floor( t ) ) { printf( "Целое!" ); }
    P.S.: спорить не советую.
     
  10. dreamer

    dreamer Гость

    lazybiz, во имя науки, прокомментируйте, пожалуйста, своё решение и скажите, чем оно лучше предложенных. А то на частных случаях мало чему научишься.
     
  11. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    dreamer
    Во имя науки. Комментирую. На счет того, что оно лучше предложенных я не говорил. Да и на счет того "что как минимум два первых метода должны работать" не оспаривал тоже. Я так же думал что они будут работать.
    В своих расчетах я тоже просчитался, хотя они и казались верными... Сейчас думаю над верным решением.
     
  12. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Пол ночи не спал. В итоге обнаружил интересную вещь. Если перебирать в цикле вещественные числа шагом скажем 0.3 то требуемого результата не получить (добавляется какой-то мусор), но если в цикле подсчитывать переменную через шаг 0.3 то результат становится правильным, и все варианты работают на ура:
    Код (C++):
    #include <stdio.h>
    #include <math.h>
    #include <float.h>

    #define STEP            0.3
    #define STEPS           31

    #define FLT_PATTERN     "%15.14f"

    void print_bin( unsigned long long v )
    {
    int i;
    for ( i = 0; i < 64; i++ ) {
    if ( i == 1 || i == 12 || i == 15 ) printf( " " );
    printf( "%d", (v >> (63 - i)) & 1 );
    }
    }

    int is_int_A( double t )
    {
    return (t - floor( t )) == 0;
    }

    int is_int_B( double t )
    {
    return (t - (int)t) == 0;
    }

    int is_int_C( double t )
    {
    return ceil( t ) == floor( t );
    }

    int is_int_D( double a )
    {
    int                 exp;
    unsigned long long  mantissa, frac, v = *((unsigned long long *)&a);

    exp = ((v >> 52) & 0x7ff) - 1023;
    mantissa = (v & 0xfffffffffffff) | 0x10000000000000;

    frac = mantissa & (((unsigned long long)1 << (52 - exp)) - 1);

    return frac == 0;
    }

    int is_int_E( double a )
    {
    int                 exp;
    unsigned long long  mantissa, v = *((unsigned long long *)&a);
    long long           frac;

    exp = ((v >> 52) & 0x7ff) - 1023;
    mantissa = (v & 0xfffffffffffff) | 0x10000000000000;

    frac = mantissa & (((unsigned long long)1 << (52 - exp)) - 1);
    frac >>= 20;

    return frac <= 0;
    }

    int is_int_F( double a )
    {
    double  a_frac, a_int;
    a_frac = modf( a, &a_int );
    return a_frac == 0;
    }

    int main()
    {
    // sizeof( double ) == 8

    int     i;
    double  t;

    printf( "t - floor( t ):\n" );
    for ( i = 0; i < STEPS; i++ ) {
    t = STEP * i;
    printf( FLT_PATTERN" %s celoe\n", t, is_int_A( t ) ? " " : " ne" );
    }

    printf( "\nt - int( t ):\n" );
    for ( i = 0; i < STEPS; i++ ) {
    t = STEP * i;
    printf( FLT_PATTERN" %s celoe\n", t, is_int_B( t ) ? " " : " ne" );
    }

    printf( "\nceil( t ) == floor( t ):\n" );
    for ( i = 0; i < STEPS; i++ ) {
    t = STEP * i;
    printf( FLT_PATTERN" %s celoe\n", t, is_int_C( t ) ? " " : " ne" );
    }

    printf( "\nmodf:\n" );
    for ( i = 0; i < STEPS; i++ ) {
    t = STEP * i;
    printf( FLT_PATTERN" %s celoe\n", t, is_int_F( t ) ? " " : " ne" );
    }

    printf( "\nfractional extract:\n" );
    for ( i = 0; i < STEPS; i++ ) {
    t = STEP * i;
    printf( FLT_PATTERN" %s celoe\n", t, is_int_D( t ) ? " " : " ne" );
    }

    printf( "\nfractional extract (hack):\n" );
    for ( i = 0; i < STEPS; i++ ) {
    t = STEP * i;
    printf( FLT_PATTERN" %s celoe ", t, is_int_E( t ) ? " " : "ne" );
    print_bin( *((unsigned long long *)&t) );
    printf( "\n" );
    }

    return 0;
    }
    Выдало:
    Код (Text):
    t - floor( t ):
    0.00000000000000    celoe
    0.30000000000000 ne celoe
    0.60000000000000 ne celoe
    0.90000000000000 ne celoe
    1.20000000000000 ne celoe
    1.50000000000000 ne celoe
    1.80000000000000 ne celoe
    2.10000000000000 ne celoe
    2.40000000000000 ne celoe
    2.70000000000000 ne celoe
    3.00000000000000    celoe
    3.30000000000000 ne celoe
    3.60000000000000 ne celoe
    3.90000000000000 ne celoe
    4.20000000000000 ne celoe
    4.50000000000000 ne celoe
    4.80000000000000 ne celoe
    5.10000000000000 ne celoe
    5.40000000000000 ne celoe
    5.70000000000000 ne celoe
    6.00000000000000    celoe
    6.30000000000000 ne celoe
    6.60000000000000 ne celoe
    6.90000000000000 ne celoe
    7.20000000000000 ne celoe
    7.50000000000000 ne celoe
    7.80000000000000 ne celoe
    8.10000000000000 ne celoe
    8.40000000000000 ne celoe
    8.70000000000000 ne celoe
    9.00000000000000    celoe

    t - int( t ):
    0.00000000000000    celoe
    0.30000000000000 ne celoe
    0.60000000000000 ne celoe
    0.90000000000000 ne celoe
    1.20000000000000 ne celoe
    1.50000000000000 ne celoe
    1.80000000000000 ne celoe
    2.10000000000000 ne celoe
    2.40000000000000 ne celoe
    2.70000000000000 ne celoe
    3.00000000000000    celoe
    3.30000000000000 ne celoe
    3.60000000000000 ne celoe
    3.90000000000000 ne celoe
    4.20000000000000 ne celoe
    4.50000000000000 ne celoe
    4.80000000000000 ne celoe
    5.10000000000000 ne celoe
    5.40000000000000 ne celoe
    5.70000000000000 ne celoe
    6.00000000000000    celoe
    6.30000000000000 ne celoe
    6.60000000000000 ne celoe
    6.90000000000000 ne celoe
    7.20000000000000 ne celoe
    7.50000000000000 ne celoe
    7.80000000000000 ne celoe
    8.10000000000000 ne celoe
    8.40000000000000 ne celoe
    8.70000000000000 ne celoe
    9.00000000000000    celoe

    ceil( t ) == floor( t ):
    0.00000000000000    celoe
    0.30000000000000 ne celoe
    0.60000000000000 ne celoe
    0.90000000000000 ne celoe
    1.20000000000000 ne celoe
    1.50000000000000 ne celoe
    1.80000000000000 ne celoe
    2.10000000000000 ne celoe
    2.40000000000000 ne celoe
    2.70000000000000 ne celoe
    3.00000000000000    celoe
    3.30000000000000 ne celoe
    3.60000000000000 ne celoe
    3.90000000000000 ne celoe
    4.20000000000000 ne celoe
    4.50000000000000 ne celoe
    4.80000000000000 ne celoe
    5.10000000000000 ne celoe
    5.40000000000000 ne celoe
    5.70000000000000 ne celoe
    6.00000000000000    celoe
    6.30000000000000 ne celoe
    6.60000000000000 ne celoe
    6.90000000000000 ne celoe
    7.20000000000000 ne celoe
    7.50000000000000 ne celoe
    7.80000000000000 ne celoe
    8.10000000000000 ne celoe
    8.40000000000000 ne celoe
    8.70000000000000 ne celoe
    9.00000000000000    celoe

    modf:
    0.00000000000000    celoe
    0.30000000000000 ne celoe
    0.60000000000000 ne celoe
    0.90000000000000 ne celoe
    1.20000000000000 ne celoe
    1.50000000000000 ne celoe
    1.80000000000000 ne celoe
    2.10000000000000 ne celoe
    2.40000000000000 ne celoe
    2.70000000000000 ne celoe
    3.00000000000000    celoe
    3.30000000000000 ne celoe
    3.60000000000000 ne celoe
    3.90000000000000 ne celoe
    4.20000000000000 ne celoe
    4.50000000000000 ne celoe
    4.80000000000000 ne celoe
    5.10000000000000 ne celoe
    5.40000000000000 ne celoe
    5.70000000000000 ne celoe
    6.00000000000000    celoe
    6.30000000000000 ne celoe
    6.60000000000000 ne celoe
    6.90000000000000 ne celoe
    7.20000000000000 ne celoe
    7.50000000000000 ne celoe
    7.80000000000000 ne celoe
    8.10000000000000 ne celoe
    8.40000000000000 ne celoe
    8.70000000000000 ne celoe
    9.00000000000000    celoe

    fractional extract:
    0.00000000000000    celoe
    0.30000000000000 ne celoe
    0.60000000000000 ne celoe
    0.90000000000000 ne celoe
    1.20000000000000 ne celoe
    1.50000000000000 ne celoe
    1.80000000000000 ne celoe
    2.10000000000000 ne celoe
    2.40000000000000 ne celoe
    2.70000000000000 ne celoe
    3.00000000000000    celoe
    3.30000000000000 ne celoe
    3.60000000000000 ne celoe
    3.90000000000000 ne celoe
    4.20000000000000 ne celoe
    4.50000000000000 ne celoe
    4.80000000000000 ne celoe
    5.10000000000000 ne celoe
    5.40000000000000 ne celoe
    5.70000000000000 ne celoe
    6.00000000000000    celoe
    6.30000000000000 ne celoe
    6.60000000000000 ne celoe
    6.90000000000000 ne celoe
    7.20000000000000 ne celoe
    7.50000000000000 ne celoe
    7.80000000000000 ne celoe
    8.10000000000000 ne celoe
    8.40000000000000 ne celoe
    8.70000000000000 ne celoe
    9.00000000000000    celoe

    fractional extract (hack):
    0.00000000000000    celoe 0 00000000000 000 0000000000000000000000000000000000000000000000000
    0.30000000000000 ne celoe 0 01111111101 001 1001100110011001100110011001100110011001100110011
    0.60000000000000 ne celoe 0 01111111110 001 1001100110011001100110011001100110011001100110011
    0.90000000000000 ne celoe 0 01111111110 110 0110011001100110011001100110011001100110011001100
    1.20000000000000 ne celoe 0 01111111111 001 1001100110011001100110011001100110011001100110011
    1.50000000000000 ne celoe 0 01111111111 100 0000000000000000000000000000000000000000000000000
    1.80000000000000 ne celoe 0 01111111111 110 0110011001100110011001100110011001100110011001100
    2.10000000000000 ne celoe 0 10000000000 000 0110011001100110011001100110011001100110011001101
    2.40000000000000 ne celoe 0 10000000000 001 1001100110011001100110011001100110011001100110011
    2.70000000000000 ne celoe 0 10000000000 010 1100110011001100110011001100110011001100110011001
    3.00000000000000    celoe 0 10000000000 100 0000000000000000000000000000000000000000000000000
    3.30000000000000 ne celoe 0 10000000000 101 0011001100110011001100110011001100110011001100110
    3.60000000000000 ne celoe 0 10000000000 110 0110011001100110011001100110011001100110011001100
    3.90000000000000 ne celoe 0 10000000000 111 1001100110011001100110011001100110011001100110011
    4.20000000000000 ne celoe 0 10000000001 000 0110011001100110011001100110011001100110011001101
    4.50000000000000 ne celoe 0 10000000001 001 0000000000000000000000000000000000000000000000000
    4.80000000000000 ne celoe 0 10000000001 001 1001100110011001100110011001100110011001100110011
    5.10000000000000 ne celoe 0 10000000001 010 0011001100110011001100110011001100110011001100110
    5.40000000000000 ne celoe 0 10000000001 010 1100110011001100110011001100110011001100110011001
    5.70000000000000 ne celoe 0 10000000001 011 0110011001100110011001100110011001100110011001101
    6.00000000000000    celoe 0 10000000001 100 0000000000000000000000000000000000000000000000000
    6.30000000000000 ne celoe 0 10000000001 100 1001100110011001100110011001100110011001100110011
    6.60000000000000 ne celoe 0 10000000001 101 0011001100110011001100110011001100110011001100110
    6.90000000000000 ne celoe 0 10000000001 101 1100110011001100110011001100110011001100110011001
    7.20000000000000 ne celoe 0 10000000001 110 0110011001100110011001100110011001100110011001100
    7.50000000000000 ne celoe 0 10000000001 111 0000000000000000000000000000000000000000000000000
    7.80000000000000 ne celoe 0 10000000001 111 1001100110011001100110011001100110011001100110011
    8.10000000000000 ne celoe 0 10000000010 000 0001100110011001100110011001100110011001100110011
    8.40000000000000 ne celoe 0 10000000010 000 0110011001100110011001100110011001100110011001101
    8.70000000000000 ne celoe 0 10000000010 000 1011001100110011001100110011001100110011001100110
    9.00000000000000    celoe 0 10000000010 001 0000000000000000000000000000000000000000000000000
     
  13. dreamer

    dreamer Гость

    Видимо, об этом я и писал выше: http://codeby.net/ipb.html?s=&sh...st&p=199025
    Просто формат представления числа не позволяет проводить даже точные операции сложения.
     
  14. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Я видел. Не думай что остался незамеченным. Просто я решил привести наглядный пример.
     
  15. IrineK

    IrineK Гость

    На мой взгляд, лучше работать не с округлением, а с переводом числа в строку.
    Ниже рассматривается два варианта: 1) число вводится пользователем, 2) число возникает при обработке "внутри" программы.

    Код (C++):
    #include <iostream>
    #include <cstring>
    using namespace std;

    //сейчас любое число вводится пользователем
    //учитывается также, что он, будучи недобрым, может ввести целое тремя способами:
    //1) без точки, 2)с точкой в конце, 3) с множеством нулей после точки

    void given_by_user()
    {
    char num[80];
    int m=0,i=0,len=0,sum=0;
    cout<<"Input any figure you like ";
    cin.getline(num,80);

    while(num[len]!='\0') len++;

    while(num[i]!='\0')
    {if(num[i]=='.')
    {m=i;
    break;}
    i++;}

    for(i=m+1;i<len;i++)
    sum+=(int)num[i];//код нуля - 48

    if(!m || (m+1)==len || sum%48==0) cout<<num<<" - integer";
    else cout<<num<<" - not integer";
    cout<<endl;
    }


    //теперь число получаем из проги. Для double целое будет просто без точки,
    //но при переводе в строку возникает только ситуация (3) из-за форматирования,
    //ее и обрабатываем

    void given_by_pro()
    {
    double d_num;
    char s_num[80];
    int i=0,m=0,sum=0,pos;

    for(;m<3;m++)
    {
    d_num= (11116+m)/11117.0;
    sprintf_s(s_num,"%20.17f",d_num);// 17 чисел после запятой - максимум точности

    while(s_num[i]!='\0')
    {if(s_num[i]=='.')
    {pos=i; break;}
    i++;}

    i=pos+1;
    while(s_num[i]!='\0')
    {sum+=(int)s_num[i];
    i++;}
    if(sum%48==0) cout<<s_num<<" - integer";
    else cout<<s_num<<" - not integer";
    cout<<endl;
    sum=0;
    }
    }

    int main()
    {
    cout<<"Double given by user\n";
    given_by_user();
    cout<<endl;
    cout<<"Double given by program\n";
    given_by_pro();
    return 0;
    }
     
  16. ierofant

    ierofant Гость

    Вы простите, но по мне это адские способы.
    Код (C++):
    #include <iostream>
    #include <cmath>

    static bool check (double _x)
    {
    double intpart;
    modf (_x, &intpart);
    return _x == intpart;
    }

    int main()
    {
    double x;
    std::cout << "x = ", std::cin >> x;

    if (check (x)) std::cout << "integer" << std::endl;
    else std::cout << "not integer" << std::endl;
    }
     
  17. dreamer

    dreamer Гость

    ierofant
    Точно весь топик прочитали?
     
  18. ierofant

    ierofant Гость

    Сначала нет, хотя теперь жалею.

    Добавлено: Так как у lazybiz есть почти такое же решение.
     
  19. solova

    solova Гость

    Cadet вы писали:Нужно узнать, является ли число типа double целым
    если я не ошибаюсь то проверять можно так
    Код (C++):
    double ostatok;
    ostatok= (("Наше число")*10)%10;
    if(ostatok!=0)  // не целое
    {
    ///////
    }
    else // целое
    {
    //////
    }
     
  20. IrineK

    IrineK Гость

    Интересно посмотреть на реакцию компилятора :) .

    Возможно, имелось в виду:
    int ostatok;
    ostatok= (int)(115.043*10)%10;

    Но в этом случае 115,043 - целое. А уж 115,0043 - тем более целое.
    Может, не все так просто?
     
Загрузка...
Статус темы:
Закрыта.

Поделиться этой страницей