• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

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

  • Автор темы Cadet
  • Дата начала
Статус
Закрыто для дальнейших ответов.
C

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) {
значит целое.
}

Как узнать!!??!!??!!??
 
D

dreamer

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

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

hosm

а что, на с++ нельзя взять дробную часть числа? и сравнить с точностью типа double (ибо с 0 сравнение может не подойти)
 
C

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.
 
D

dreamer

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

hosm

я имела в виду нечто стандартное в какой-то либ языка. Гугль указан на modf, например.
 
D

dreamer

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

dreamer

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

lazybiz

dreamer
Во имя науки. Комментирую. На счет того, что оно лучше предложенных я не говорил. Да и на счет того "что как минимум два первых метода должны работать" не оспаривал тоже. Я так же думал что они будут работать.
В своих расчетах я тоже просчитался, хотя они и казались верными... Сейчас думаю над верным решением.
 
L

lazybiz

Пол ночи не спал. В итоге обнаружил интересную вещь. Если перебирать в цикле вещественные числа шагом скажем 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;
}

Выдало:
Код:
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
 
D

dreamer

Если перебирать в цикле вещественные числа шагом скажем 0.3 то требуемого результата не получить (добавляется какой-то мусор), но если в цикле подсчитывать переменную через шаг 0.3 то результат становится правильным, и все варианты работают на ура:
Видимо, об этом я и писал выше: link removed
Просто формат представления числа не позволяет проводить даже точные операции сложения.
 
I

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;
}
 
I

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;
}
 
I

ierofant

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

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

solova

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

IrineK

double ostatok;
ostatok= (("Наше число")*10)%10;

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

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

Но в этом случае 115,043 - целое. А уж 115,0043 - тем более целое.
Может, не все так просто?
 
Статус
Закрыто для дальнейших ответов.
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!