Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 05.04.2010, 11:53   #1
Александе еть я
Пользователь
 
Регистрация: 18.10.2009
Сообщений: 29
По умолчанию с++

подскажите пожалуйста как можно проверить в с++ целое число или дробное... в паскале есть функция транк...если такая в си..заранее спасибо..
Александе еть я вне форума Ответить с цитированием
Старый 05.04.2010, 12:08   #2
ds.Dante
Старожил
 
Аватар для ds.Dante
 
Регистрация: 06.08.2009
Сообщений: 2,992
По умолчанию

Теоретически можно так:

Код:
float x;
if (x == (int)x)
    ...
Но есть один нюанс:сопроцессор всегда считает с некоторой погрешностью, поэтому после
x = 0.5+0.5;
в результате может получиться 0.99999999 или 1.00000001. Лучше делать как-нибудь так:

Код:
#define epsilon 0.00001

...

float x = 0.5+0.5;
if (abs(x-(int)(x+epsilon)) < 2*epsilon)
    ...
Если сделать просто (int)x, то 0.99999999 округлится до нуля, поэтому тут нужно x+epsilon. Если такая проверка проводится много раз, её можно выделить в отдельную функцию bool IsIntegral (double x).
ds.Dante вне форума Ответить с цитированием
Старый 05.04.2010, 15:58   #3
Vago
Форумчанин
 
Регистрация: 15.01.2010
Сообщений: 948
По умолчанию

Цитата:
Сообщение от ds.Dante Посмотреть сообщение
Код:
#define epsilon 0.00001
В хидере float.h для этого существуют предопределённые константы FLT_EPSILON и DBL_EPSILON .
Vago вне форума Ответить с цитированием
Старый 06.04.2010, 11:26   #4
ds.Dante
Старожил
 
Аватар для ds.Dante
 
Регистрация: 06.08.2009
Сообщений: 2,992
По умолчанию

FLT_EPSILON и DBL_EPSILON - это погрешность при значениях, близких к 1.

То есть, если у нас выражение "x = 1000.5 + 0.5", то эти константы окажутся слишком маленькими. В качестве эпсилон надо взять максимальное число, которое не вносит существенной разницы в результат (которое практически можно считать целым)
ds.Dante вне форума Ответить с цитированием
Старый 06.04.2010, 12:49   #5
Vago
Форумчанин
 
Регистрация: 15.01.2010
Сообщений: 948
По умолчанию

Цитата:
Сообщение от ds.Dante Посмотреть сообщение
FLT_EPSILON и DBL_EPSILON - это погрешность при значениях, близких к 1.
Совершенно верно. А что, выражение
Код:
fabs( x - (double)(int)(x) )
Может стать больше единицы? Тем более, на 10 порядков больше?...
Код:
#include <stdio.h>
#include <math.h>
#include <float.h>

bool isInt( double x ) {

   double de = fabs( x - (double)(int)(x) );
   return ( de >= 0. ? de < DBL_EPSILON : (1. - de) < DBL_EPSILON );

}


int main() {

   const char* czResult;

   double a = 
//1      -100.9999999999999995
//2      100.9999999995
//3      -10000.0005
//4      -100000000.0000000001
      100000000.5 + 0.5
      ;

   czResult = isInt( a ) ? "almost integer." : "clearly float.";
   printf( "%.13g is %s\n", a, czResult );

   return 0;

}
Другое дело, что принудительное преобразование в int сужает диапазон чисел, которые можно по такому алгоритму проверить. Но на это мы пока не обращаем внимания...

Added 11:44 CET
А кто, собственно, нас, вообще, заставляет пользоваться int?!...
Код:
bool isInt( double x ) {

   double de = fabs( x - floor( x ) );
   return ( de >= 0. ? de < DBL_EPSILON : (1. - de) < DBL_EPSILON );

}

Последний раз редактировалось Vago; 06.04.2010 в 13:45.
Vago вне форума Ответить с цитированием
Старый 06.04.2010, 14:09   #6
ds.Dante
Старожил
 
Аватар для ds.Dante
 
Регистрация: 06.08.2009
Сообщений: 2,992
По умолчанию

Цитата:
Сообщение от Vago Посмотреть сообщение
А что, выражение
Код:
fabs( x - (double)(int)(x) )
Может стать больше единицы?
Нет, но для ошибки достаточно, чтобы было больше DBL_EPSILON.


А теперь практическая проверка:
Код:
#include <iostream>
#include <cmath>
#include <float.h>
using namespace std;

#define EPSILON 0.00001

bool IsIntegral_byDante (double x)
{
	if (abs(x-(int)(x+EPSILON)) < 2*EPSILON)
		return true;
	else
		return false;
}

bool IsIntegral_byVago (double x)
{
   double de = fabs( x - (double)(int)(x) );
   return ( de >= 0. ? de < DBL_EPSILON : (1. - de) < DBL_EPSILON );
}

void main()
{
	double x=10;
	for (int i=0; i<100; i++)
		x -= 0.1;

	cout << x << endl;
	cout << IsIntegral_byDante (x) << endl;
	cout << IsIntegral_byVago (x) << endl;
	cin.get();
}
Вывод на экран:
Цитата:
1.87905e-014
1
0
Если взять второй твой вариант (с floor() вместо приведения), ничего не изменится. Если в моей функции подставить DBL_EPSILON, она тоже выдаст неверный результат.


UPD: я сделал наиболее точную и "правильную" функцию без грязных хаков. Этот вариант я и предлагаю автору топика (нужно только подобрать подходящий EPSILON).
Код:
bool IsIntegral (double x)
{
	double de;

	if (x-(int)x < 0.5)
		de = x - (int)x;
	else
		de = x - (int)(x+1);

	if (de < EPSILON)
		return true;
	else
		return false;
}

Последний раз редактировалось ds.Dante; 06.04.2010 в 14:21.
ds.Dante вне форума Ответить с цитированием
Старый 06.04.2010, 14:44   #7
Vago
Форумчанин
 
Регистрация: 15.01.2010
Сообщений: 948
По умолчанию

Цитата:
Сообщение от ds.Dante Посмотреть сообщение
нужно только подобрать подходящий EPSILON
Золотые слова!! ))) Только в реальной инженерной задаче сделать это ой как трудно! Что значит "неверный результат"? )) "Результат с требуемой точностью" - так здесь вернее будет сказать. Ты, просто, успокаиваешься при погрешности чуть меньше 10^-5, а я - 10^-21 Подставим, как компромисс, FLT_EPSILON (10^-7), и обе п/п выдадут "Ура, целый ноль!"

Последний раз редактировалось Vago; 06.04.2010 в 14:46.
Vago вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц