Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Преобразование типа double в int 
V
    Опции темы
jimbo
Дата 24.2.2011, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 18.6.2009
Где: Южно-Сахалинск

Репутация: нет
Всего: нет



Привет всем. как преобразовать число из типа double в тип int.

Windows Vista SP2, MSVS 2008 SP1


Вот такой код не работает на моем компе. если делать округление функцией ceil то все нормально переводится. 

Код

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

int _tmain()
{
    double p = 0.9888;
    double sl = 0.9885;
    double st = pow((double)10,4);
    double a = (p-sl)*st;
    
    //int c = ceil(a);
    int b = a;
    printf("%lf,%d\n",a,b);
    return 0;
}


Вопрос наверно такой: как определить когда надо использовать округление а когда не надо?

Это сообщение отредактировал(а) jimbo - 24.2.2011, 14:47
--------------------
Я не играю в шахматы - в шахматах я борюсь. А.А.Алехин
PM MAIL WWW   Вверх
Modul
Дата 24.2.2011, 15:05 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 238
Регистрация: 17.2.2006

Репутация: нет
Всего: нет



А Вы сами напишите, что думаете. А сообщество подскажет дальше...
--------------------
I'll be back !
PM MAIL   Вверх
mes
Дата 24.2.2011, 15:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(jimbo @  24.2.2011,  13:45 Найти цитируемый пост)
Вот такой код не работает на моем компе. 

а как именно не работает - это, наверно военная тайна..

Цитата(jimbo @  24.2.2011,  13:45 Найти цитируемый пост)
как определить когда надо использовать округление а когда не надо?

зависит от задачи, которую Вы забыли сформулировать.. 


--------------------
PM MAIL WWW   Вверх
jimbo
Дата 24.2.2011, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 18.6.2009
Где: Южно-Сахалинск

Репутация: нет
Всего: нет



Цитата(mes @ 24.2.2011,  15:56)
Цитата(jimbo @  24.2.2011,  13:45 Найти цитируемый пост)
Вот такой код не работает на моем компе. 

а как именно не работает - это, наверно военная тайна..

Ну почему же? не тайна.

я запускал этот код на своем компе и на соседнем, там стоит хр.

всегда результат был таким:
3.000000,2


Математическое выражение (0.9888 - 0.9885) * 10^4 =  0.0003 * 10000 = 3

в типе double это число получается 2,9999999999999 
с приведением к типу int получается 2. 
Ну не логично же, нет?

Вопрос из сабжа. как преобразовать тип double в int "по-человечески" ?
--------------------
Я не играю в шахматы - в шахматах я борюсь. А.А.Алехин
PM MAIL WWW   Вверх
borisbn
Дата 24.2.2011, 16:23 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



jimbo, запусти вот это
Код

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

int main()
{
    double two_and_1 = 2.1;
    double two_and_9 = 2.9; 
    printf( "two_and_1 = %lf\n", two_and_1 );
    printf( "two_and_9 = %lf\n", two_and_9 );
    int i_two_and_1 = (int)two_and_1;
    int i_two_and_9 = (int)two_and_9; 
    printf( "i_two_and_1 = %d\n", i_two_and_1 );
    printf( "i_two_and_9 = %d\n", i_two_and_9 );
    int ceil_two_and_1 = ceil( two_and_1 );
    int ceil_two_and_9 = ceil( two_and_9 ); 
    printf( "ceil_two_and_1 = %d\n", ceil_two_and_1 );
    printf( "ceil_two_and_9 = %d\n", ceil_two_and_9 );

    int round_two_and_1 = (int)( two_and_1 + 0.5 );
    int round_two_and_9 = (int)( two_and_9 + 0.5 );
    printf( "round_two_and_1 = %d\n", round_two_and_1 );
    printf( "round_two_and_9 = %d\n", round_two_and_9 );

    return 0;
}

и, думаю, будет всё понятно

Это сообщение отредактировал(а) borisbn - 24.2.2011, 16:29


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 24.2.2011, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(jimbo @  24.2.2011,  15:06 Найти цитируемый пост)
как преобразовать тип double в int "по-человечески" ? 

это не преобразование, а округление.. стандартной функции round нет.. гугль поможет найти библиотечку, где такая есть..
если хотите самостоятельно реализовать, то правила простые :
Цитата

Roundings to nearest
Round to nearest, ties to even – rounds to the nearest value; if the number falls midway it is rounded to the nearest value with an even (zero) least significant bit, which occurs 50% of the time; this is the default algorithm for binary floating-point and the recommended default for decimal
Round to nearest, ties away from zero – rounds to the nearest value; if the number falls midway it is rounded to the nearest value above (for positive numbers) or below (for negative numbers)

http://en.wikipedia.org/wiki/IEEE_754-2008


--------------------
PM MAIL WWW   Вверх
jimbo
Дата 24.2.2011, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 18.6.2009
Где: Южно-Сахалинск

Репутация: нет
Всего: нет



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

Тут одинаковый код только цифры разные. У меня на компе ii = 3 а с = 2. У вас не так? Запустите и посмотрите. ВСЕГДА должно быть 3 - это чисто математически верно, нет других вариантов. Компьютер же считает иначе. я так полагаю из-за хранения типа double, получается неточность, в итоге инт у нас равен 2. Потом по коду я перевожу дабл в строку и строку в инт. результат ошеломляющий и блин верный.  дубль два - как по-человечески перевести тип дабл в инт. Есть ли возможность задать типу дабл точность до 10 знаков после запятой или как-то избегать ответов "no" в коде. Считайте что числа `p` и `sl` всегда разные.

Код

        double t = 0.0005;
    double k = 0.0002;
    double dif = t-k;

    double d_dif = dif * 10000;

    int ii = (int)d_dif;
    printf("%lf,%d\n",d_dif,ii);

    double p = 0.9888;
    double sl = 0.9885;
    double a = (p-sl)*10000;    
    
    int c = a;        
    printf("%lf,%d\n",a,c);

    if(a >= 3)
    {
        printf("yes\n");
    }
    else printf("no\n");

char ss[32];
    sprintf_s(ss,31,"%lf",a);
    int dd = atoi(ss);
    printf("%d,%lf\n",dd,a);

    if(dd >= 3)
    {
        printf("yes\n");
    }
    else printf("no\n");

--------------------
Я не играю в шахматы - в шахматах я борюсь. А.А.Алехин
PM MAIL WWW   Вверх
mes
Дата 24.2.2011, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(jimbo @  24.2.2011,  15:51 Найти цитируемый пост)
Компьютер же считает иначе. я так полагаю из-за хранения типа double, получается неточность, в итоге инт у нас равен 2.

из за способа округления.. стандартных только два : 
Цитата(floor)

Returns the largest integral value that is not greater than x.

http://www.cplusplus.com/reference/clibrary/cmath/floor/

Цитата(ceil)

Returns the smallest integral value that is not less than x.

http://www.cplusplus.com/reference/clibrary/cmath/ceil/

оба они Вам не подходят.. 

Цитата

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



--------------------
PM MAIL WWW   Вверх
jimbo
Дата 24.2.2011, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 18.6.2009
Где: Южно-Сахалинск

Репутация: нет
Всего: нет



я реализовал через строки. Но боже мой, какой тупизм!!
--------------------
Я не играю в шахматы - в шахматах я борюсь. А.А.Алехин
PM MAIL WWW   Вверх
borisbn
Дата 24.2.2011, 18:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(jimbo @  24.2.2011,  17:55 Найти цитируемый пост)
я реализовал через строки. Но боже мой, какой тупизм!!

действительно, не лучшее решение

Цитата(jimbo @  24.2.2011,  16:51 Найти цитируемый пост)
в итоге инт у нас равен 2

точнее не int, а результат Вашего округления (читай отбрасывания дробной части).
если преобразовывать так
Код

int ii = (int)(double_value + 0.5);

то будет правильное округление

и еще, написав, double p = 0.9888; Вы не получите десятичное число 0.9888 в переменной p. отсюда, скорее всего, и вопросы.

jimbo, объясните суть задачи, и Вам, скорее всего, помогут её решить...

Это сообщение отредактировал(а) borisbn - 24.2.2011, 18:08


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 24.2.2011, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(borisbn @  24.2.2011,  17:06 Найти цитируемый пост)
то будет правильное округление

для отрицательных тоже ?  smile

Добавлено через 2 минуты и 10 секунд
Цитата(jimbo @  24.2.2011,  16:55 Найти цитируемый пост)
Но боже мой, какой тупизм!! 

имхо, Вам проще всего будет реализовать на основе modf

Добавлено через 3 минуты и 6 секунд
или доработать приведенное borisbn..


--------------------
PM MAIL WWW   Вверх
jimbo
Дата 24.2.2011, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 18.6.2009
Где: Южно-Сахалинск

Репутация: нет
Всего: нет



Задача сводится к преобразованию числа типа double к числу типа int. Причем не так как делает это компилятор (отбрасыванием дробной части) а математически. Разряд максимальный после запятой  - 10. То есть не надо супер приближений

Есть объект у которого есть метрика value. Она вещественная. Есть меняющийся стандарт. у него также есть метрика st_value. Есть минимальное отклонение st. Есть порог чувствительности level.

В течение времени можно создать много много объектов и у каждого будет своя value. Когда у какого-либо объекта метрика приближается к текущему стандату ближе чем порог чувствительности level необходимо обработать данные. 

Теперь смотрим. есть объект с value 0.9888. Текущий стандарт 0.9885. Порог чувствительности 3 минимальных отклонения. Минимальное отклонение 0.0001 (зачастую является степенью 10). Мне надо обработать данные судя по математическим числам, программа же моя не реагирует, потому что 2 не больше 3.

Код

if( (0,9888 - 0,9885 ) * 10^4 >= 3 ) 



Вот и получается что
Код


double result = (this->GetValue() - st_obj->GetValue())*pow(10.0,st_obj->Get10Dgr());
            char bs[64];
            sprintf_s(bs,63,"%lf",result);
            int levels = atoi(bs);
            if( levels >=st_obj->GetLevel()) Process()


Добавлено через 11 минут и 3 секунды
Цитата(mes @ 24.2.2011,  18:11)
Добавлено @ 18:13
Цитата(jimbo @  24.2.2011,  16:55 Найти цитируемый пост)
Но боже мой, какой тупизм!! 

имхо, Вам проще всего будет реализовать на основе modf

Или я не понял как пользоваться Modf или вот

Код


double a = (0.9888-0.9885)*10000;
double part;
double bbc = modf(a,&part);

out:
a = 2.99999
part = 2.00000
bbc = 0.99999

--------------------
Я не играю в шахматы - в шахматах я борюсь. А.А.Алехин
PM MAIL WWW   Вверх
mes
Дата 24.2.2011, 19:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(jimbo @  24.2.2011,  17:28 Найти цитируемый пост)
или вот

теперь анализируйте дробную часть, и четность целой части (необязательно) и на основе это возвращайте правильно округленное значение..

Добавлено через 3 минуты и 48 секунд
Цитата(jimbo @  24.2.2011,  17:28 Найти цитируемый пост)
, потому что 2 не больше 3

вместо 3 (целое) используйте 3.0 или просто 3. (с точкой) и не надо будет округлять..





--------------------
PM MAIL WWW   Вверх
borisbn
Дата 24.2.2011, 22:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(mes @  24.2.2011,  18:11 Найти цитируемый пост)
для отрицательных тоже ?

быстрее (ответить в форум) - не значит правильнее smile smile smile
Код

int myRound( double d ) {
  int sign = (d >=0) : 1 : -1;
  return (int)(d + sign * 0.5);
}

jimbo, IMHO так должно работать 
Код

  double result = (this->GetValue() - st_obj->GetValue())*pow(10.0,st_obj->Get10Dgr());
  int levels = myRound( result );
  if( levels >=st_obj->GetLevel()) Process()


Это сообщение отредактировал(а) borisbn - 24.2.2011, 22:18


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
xvr
Дата 25.2.2011, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(jimbo @  24.2.2011,  18:28 Найти цитируемый пост)
Вот и получается что
Код

double result = (this->GetValue() - st_obj->GetValue())*pow(10.0,st_obj->Get10Dgr());
            char bs[64];
            sprintf_s(bs,63,"%lf",result);
            int levels = atoi(bs);
            if( levels >=st_obj->GetLevel()) Process()
А преобразовывать именно double в int для сравнения (а не наоборот) религия требует?  smile 
Код

double result = (this->GetValue() - st_obj->GetValue())*pow(10.0,st_obj->Get10Dgr());
            if( result >=st_obj->GetLevel()) Process()


PM MAIL   Вверх
миг
Дата 25.2.2011, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 15.9.2008

Репутация: нет
Всего: 1



Цитата(jimbo @ 24.2.2011,  17:55)
я реализовал через строки. Но боже мой, какой тупизм!!

 smile 

Код

int fun(double x) 
{
   int y;
   y=x;
   if(x-(double)y>0.333333)y++;
   return y;
}

--------------------
Oaks may fall when reeds stand the storm.
PM MAIL   Вверх
Anton86
Дата 13.12.2011, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 13.12.2011

Репутация: нет
Всего: нет



Помогите разобраться с преобразованием типов. Есть код:

Код

 #include <iostream>

 using namespace std;

 int main()
 {
 float p0 = 121.1;
 float p1 = 121.2;
 float p2 = 121.3;
 int l0, l1, l2;

 l0 = (int)(p0 * 10.0);
 l1 = (int)(p1 * 10.0);
 l2 = (int)(p2 * 10.0);
 cout << l0 << endl << l1 << endl << l2 << endl;
 return 0;
 }


 вывод программы:

 1210
 1211
 1213

 Насколько я представляю правила преобразования типов, при проведении промежуточных вычислений, при вычислении l0 - l2, сначала вычисляется значение в скобках типа float, затем результат преобразовывается к int. таким образом l должны быть l0=(int)(1211.0f)=1211, l1=(int)(1212.0f)=1212, l2=(int)(1213.0f)=1213. Объясните в чем дело.
PM MAIL   Вверх
volatile
Дата 13.12.2011, 23:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(Anton86 @  13.12.2011,  19:29 Найти цитируемый пост)
 float p0 = 121.1;

в силу того что десятичные дроби, нельзя точно представить в float, здесь
p0 = 121.099999...
умножаем на 10, получаем:
1210.99999...
ну а (int), просто берет целую чать, не округляя, т.е 1210.
чтоб этого избежать, нужно округлять.
Про округление, почитайте на предыдущей странице, там даже сторонние библиотеки предлагают... smile 

Простой (и имхо вполне нормальный) способ округления:
Код

int res = (int) floor (float_value + .5);

PM MAIL   Вверх
Anton86
Дата 14.12.2011, 19:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 13.12.2011

Репутация: нет
Всего: нет



спасибо за ответ. С округлением типа floor и fmod все ясно, интересуют именно промежуточные вычисления и преобразования типов при этом. Например, почему код

Код
 
#include <iostream>

using namespace std;

int main()
{
    float p0 = 121.1;
    float p1;
    int l0;

    p1 = p0 * 10.0;
    l0 = (int)p1;
    
    cout << l0 << endl;

    return 0;
}


даст 1211?

Это сообщение отредактировал(а) Anton86 - 14.12.2011, 19:51
PM MAIL   Вверх
volatile
Дата 14.12.2011, 23:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Anton86, я же уже писал:
Цитата(volatile @  13.12.2011,  23:54 Найти цитируемый пост)
в силу того что десятичные дроби, нельзя точно представить в float

Все зависит от последнего значащего бита, а его вычисление зависит от реализации.
Ваш код на одной платформе может дать 1210, на другой 1211
Это очень не надежный код

Код

    float p0 = 121.1;
    float p1;
    int l0;

    p1 = p0 * 10.0;
    l0 = (int) floor (p1 + .5);
    cout << l0 << endl;


Вот этот код, гарантировано, на любой платформе даст 1211
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1237 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.