[c++] взять целую часть числа?

t332

как? есть ли какая-нибудь функция!?

hoha32

a = (int)b;

t332

у меня так не работает!
на самом деле решается задача:
if ( d - (int)d == 0. )
{
// а сюды не всегда заходит
}
как быть?

hoha32

А так, что даже если d кажется целым, но типа double - это равенство имеет тенденцию вообще не выполняться.
Так что думать дальше.

boris1963-11

Извращённый способ - самой посчитать целую часть числа (делим пополам и т.д., пока не дойдём до нуля, потом идём назад, проверяя остатки). А потом смотрим, близка разница к нулю или нет.
А сравнивать real с integer, по моему, бесмысленно, там из-за машинного нуля вполне может не зайти туда. Тогда уж сравнивать, меньше ли разность, чем точность real.

Tasha2201

а откуда возьмется разность меньшая точности real?

hoha32

Скорее, имеет смысл сравнивать с точностью шага.
2Ink: В проге есть какой-то шаг, я так понимаю?

t332

есть...
значит нельзя?
спасибо!

boris1963-11

Ну не меньше тогда, например, а <=.
Просто разность двух равных чисел разного типа имеет свойство почти никогда не равняться нулю. Да и одинакового дробного - тоже

hoha32

Как ты хочешь сделать (точное равенство) - нельзя.
Но можно попытаться добиться требуемого эффекта с помощью неравенства. Просто написать что-то вроде
if (abs(d - (int)d) < step / 10.)

t332

нашли:
dd = (intd + 0.0000000001)
if ( d - dd == 0. )
{
// OK!
}

t332

внимание! это работает только в случае если d очень близко к целому

hoha32

а с
dd = (int)d;
не работает?

t332

или не только ...
короче, заработало!
спасибо всем!

boris1963-11

Лучше вместо константы 0.000***01 спользуй в программе константу, которую она посчитает. А то с этим возможны всякие глюки при переходе на другую версию срества разработки

Boris1980

0.0000000001
Для других начальных данных придется другую константу подбирать.
ИМХО, не вариант.

t332

полный вариант:
eps = 1.
while (eps/2.)
eps /= 2.;
dd = (intd + eps);
if ( d - dd <= eps )
{
// OK!
}

boris1963-11

Вот так нормально подбирать 0.

sobleb

Попробуй так:

if ( d - (intd+0.5) == 1. )
{
твой код;
}

hoha32

Это уже округление до ближайшего целого, а не взятие целой части. К тому же выдающее фигню в случае отрицательного d.

sobleb

ему ж главное проверить, является ли целым...
а в случае отрицательных - модуль дописать...

maggi14

Народ, сравнивать дробные на равенство вообще нельзя. Мне как-то устроили такой тренинг: когда самые очевидны баги были исключены теми методами, что вы описали, и еще разными другими, стали всплывать изощренные баги. Единственный безгеморрный способ - это сравнивать на неравенство, предварительно введя допустимую погрешность.

boris1963-11

теми методами, что вы описали
Тут как раз и написано - считаем допустимую погрешность, и сравниваем модуль разности и эту погрешность. По неравенству

maggi14

Естественно, я не имел в виду последний пост Инк. Просто меня тогда так впечатлил этот факт (что сравнивать на равенство нельзя даже с изощоениями что я решил поделиться переполнявшими меня чувствами

bleyman

Это неправильный вариант.
Несколько более правильный вариант:
double one = 1.0;
double eps = 1.0;
while (one + eps/2. != one)
{
eps /= 2.;
}
...
delta = eps * d;
if (d - (int)d <= delta)
{
return true;
}
Для отрицательных d нужно подпадчить.
Где-то в архиве есть обсуждение того, почему так.

boris1963-11

Если d произвольное, достаточно просто, по-моему, в последнем условии сравнивать не d - (int)d, а его модуль

bleyman

На самом деле взять модуль d перед вычислением дельты и не париццо.

Ivan8209


NAME
modf -- extract signed integral and fractional values from floating-point
number

LIBRARY
Standard C Library (libc, -lc)

SYNOPSIS
#include <math.h>

double
modf(double value, double *iptr);

DESCRIPTION
The modf function breaks the argument value into integral and frac-
tional parts, each of which has the same sign as the argument. It stores
the integral part as a double in the object pointed to by iptr.

---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."
Karel Capek

Bird_V

Вот именно, fmod либо floor/ceil...

matorina

double d = 1.2345;

if ( (d - int)d) * 1.0) == 0 ) { ... }
хе...

matorina

нет, лучше заменить 0 на 0.0!

boris1963-11

Повторяю,единственное, что известно про сравнение на _равенство_ нецелых чисел - если они не совпадают, равенство не посчитается. Но и если они совпадают, равенство скорее всего тоже не посчитается. Так что делай там хоть 0.00000, проблему ты этим не решишь, тут надо сравнивать, больше модуль разности чем эпсилон, или нет.

vredina343416

double d = 1.2345;
if ( d == int)d) * 1.0 ) { ... }
а так?
// Holden_Offline

anton7805

а че, floor(d) нельзя использовать?

freezer

(d>0 ? floor(d) : ceil(d

bleyman

Что за агностические представления о копьютерах?
У double/float есть вполне определённый формат, и любое вещественное число из области значений представляется в нём единственным образом. Равенство проверяется побитово. Никакой магии и запросов к Высшей Силе ни при вычислениях ни при проверке равенства не происходит, результаты всех действий жОстко детерминированы стандартом.
Проблема в том, что ошибки округления очень сложно учитывать в численных методах, а они могут существенно влиять. Так что if (a == b) не выполняется когда а != b _на самом деле_, а в некоторых алгоритмах они никогда не смогут стать равными.
Например,
double a = 1;
double b = 2;
while (a != b)
{
b -= (b - a)/4.0;
}
Цикл никогда не остановится. Потому что a _действительно_ будет меньше b, а в какой-то момент b перестанет уменьшаться.
Далее, в случае float где-то на числах порядка 10^8 - 10^9 начинают пропускаться нечётные числа, то есть точность вылезает до уровня целых.
Почитай стандарт, тебе станет намного легче.

Dasar

> любое вещественное число из области значений
Что такое вещ. число из области значений?
1/7 - из области значений float-а или нет?
ps
например:

Console.WriteLine(10.0/7 == (1.0/9 + 2.0/63) * 10)
выдает false

Console.WriteLine(10.0/7 - (1.0/9 + 2.0/63) * 10);
выдает 2,22044604925031E-16

bleyman

Найди во фразе "и любое вещественное число из области значений представляется в нём единственным образом." словосочетание "взаимно однозначно". Нашёл? Нет? И я нет. Потому что его там нет.
А то, что иногда float(r1) + float(r2) != float(r1 + r2) (где r1 и r2 - некоторые вещественные числа) и называется ошибками округления. Привет.

yolki

>Что такое вещ. число из области значений?
>1/7 - из области значений float-а или нет?
Оно из области знаний. и оно единственным образом представляется в float. другое дело что много чисел из области знаний представляется таким же способом.

Console.WriteLine(10.0/7 == (1.0/9 + 2.0/63) * 10)
выдает false
Это ни о чём не говорит. лишь о том, что арифметика этих представлений не совпадает с привычной нам

Console.WriteLine(10.0/7 - (1.0/9 + 2.0/63) * 10);
выдает 2,22044604925031E-16
Логично - арифметика double, а не float.
Если я каким-то образом извернусь и сделаю свою VM, которая будет оперировать на long double, то ошибка будет ~1e-21

boris1963-11

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

yolki

floor(x ceil(x) - это всё, что может тебе помочь.
узнать, целое ли число x (типа float/double) в общем случае очень сложно и для некоторых чисел невозможно.
Например, начиная с некоторого X все числа целые

Dasar

> Оно из области знаний. и оно единственным образом представляется в float. другое дело что много чисел из области знаний представляется таким же способом.
Вообще-то нет.
В примере, я привел две записи одного и того же числа 10/7 - они не совпали.
Вывод одно и тоже число может быть представлено несколькими машинными числами.
> Это ни о чём не говорит. лишь о том, что арифметика этих представлений не совпадает с привычной нам
Это говорит о том, что аналитически равные числа - за счет разной записи - в машине могут быть представлены уже в другом виде.

Dasar

Есть числа, которые невозможно записать напрямую в машинном виде, и они записываются косвенно через выражения - при этом в зависимости от выбранного выражения - одно и то же число в машине будет представлено по разному.

bleyman

Нет.
void zz(int d)
{
float f = (float)d;
if (f == (int)f)
{
...
}
}
сработает ВСЕГДА. Вообще всегда. Совсем всегда.
Все эти проверки (в том числе и та, которую я писал) на самом деле пытаются исправлять ошибки твоего Численного Метода.

bleyman

>Есть числа, которые невозможно записать напрямую в машинном виде, и они записываются косвенно через выражения - при этом в зависимости от выбранного выражения - одно и то же число в машине будет представлено по разному.
Да, разные способы вычисления приближённых величин дадут разные результаты, тебя это удивляет? Однако значение float f = 1/3 детерминированно. Если ты в своём выражении в явном виде напишешь места, где происходит округление, то есть разнесёшь его на простые инструкции вида "переменная = переменная операция переменная", то всё что ты будешь получать на каждом этапе тоже будет жёстко детерминированно.
Я это уже в посте наверху сказал: все эти сравнения с эпсилоном - это исправление ошибок численного метода, и подходить к ним нужно именно с этой позиции.

Dasar

> сработает ВСЕГДА. Вообще всегда. Совсем всегда.
не всегда, конечно.

float f = int.MaxValue;
Console.WriteLine(f == (int)f);

Выдает false

bleyman

ггг
А это уже инт глючит =)
(float)int.MaxValue чуть больше чем int.MaxValue, поэтому когда её в инт обратно кастишь, получается отрицательное число. Вот. Я что-то об этом не подумал.
Оставить комментарий
Имя или ник:
Комментарий: