[c++] взять целую часть числа?
a = (int)b;
на самом деле решается задача:
if ( d - (int)d == 0. )
{
// а сюды не всегда заходит
}
как быть?
Так что думать дальше.
А сравнивать real с integer, по моему, бесмысленно, там из-за машинного нуля вполне может не зайти туда. Тогда уж сравнивать, меньше ли разность, чем точность real.
а откуда возьмется разность меньшая точности real?
2Ink: В проге есть какой-то шаг, я так понимаю?
значит нельзя?
спасибо!
Просто разность двух равных чисел разного типа имеет свойство почти никогда не равняться нулю. Да и одинакового дробного - тоже
Но можно попытаться добиться требуемого эффекта с помощью неравенства. Просто написать что-то вроде
if (abs(d - (int)d) < step / 10.)
dd = (intd + 0.0000000001)
if ( d - dd == 0. )
{
// OK!
}
внимание! это работает только в случае если d очень близко к целому
dd = (int)d;
не работает?
короче, заработало!
спасибо всем!
Лучше вместо константы 0.000***01 спользуй в программе константу, которую она посчитает. А то с этим возможны всякие глюки при переходе на другую версию срества разработки
0.0000000001Для других начальных данных придется другую константу подбирать.
ИМХО, не вариант.
eps = 1.
while (eps/2.)
eps /= 2.;
dd = (intd + eps);
if ( d - dd <= eps )
{
// OK!
}
Вот так нормально подбирать 0.
if ( d - (intd+0.5) == 1. )
{
твой код;
}
Это уже округление до ближайшего целого, а не взятие целой части. К тому же выдающее фигню в случае отрицательного d.
а в случае отрицательных - модуль дописать...
Народ, сравнивать дробные на равенство вообще нельзя. Мне как-то устроили такой тренинг: когда самые очевидны баги были исключены теми методами, что вы описали, и еще разными другими, стали всплывать изощренные баги. Единственный безгеморрный способ - это сравнивать на неравенство, предварительно введя допустимую погрешность.
теми методами, что вы описалиТут как раз и написано - считаем допустимую погрешность, и сравниваем модуль разности и эту погрешность. По неравенству
Естественно, я не имел в виду последний пост Инк. Просто меня тогда так впечатлил этот факт (что сравнивать на равенство нельзя даже с изощоениями что я решил поделиться переполнявшими меня чувствами
Несколько более правильный вариант:
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 нужно подпадчить.
Где-то в архиве есть обсуждение того, почему так.
Если d произвольное, достаточно просто, по-моему, в последнем условии сравнивать не d - (int)d, а его модуль
На самом деле взять модуль d перед вычислением дельты и не париццо.
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
Вот именно, fmod либо floor/ceil...
хе...
if ( (d - int)d) * 1.0) == 0 ) { ... }
нет, лучше заменить 0 на 0.0!
Повторяю,единственное, что известно про сравнение на _равенство_ нецелых чисел - если они не совпадают, равенство не посчитается. Но и если они совпадают, равенство скорее всего тоже не посчитается. Так что делай там хоть 0.00000, проблему ты этим не решишь, тут надо сравнивать, больше модуль разности чем эпсилон, или нет.
double d = 1.2345;а так?
if ( d == int)d) * 1.0 ) { ... }
// Holden_Offline
а че, floor(d) нельзя использовать?
(d>0 ? floor(d) : ceil(d
У 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 начинают пропускаться нечётные числа, то есть точность вылезает до уровня целых.
Почитай стандарт, тебе станет намного легче.
Что такое вещ. число из области значений?
1/7 - из области значений float-а или нет?
ps
например:
выдает false
Console.WriteLine(10.0/7 == (1.0/9 + 2.0/63) * 10)
выдает 2,22044604925031E-16
Console.WriteLine(10.0/7 - (1.0/9 + 2.0/63) * 10);
А то, что иногда float(r1) + float(r2) != float(r1 + r2) (где r1 и r2 - некоторые вещественные числа) и называется ошибками округления. Привет.
>1/7 - из области значений float-а или нет?
Оно из области знаний. и оно единственным образом представляется в float. другое дело что много чисел из области знаний представляется таким же способом.
Это ни о чём не говорит. лишь о том, что арифметика этих представлений не совпадает с привычной нам
Console.WriteLine(10.0/7 == (1.0/9 + 2.0/63) * 10)
выдает false
Логично - арифметика double, а не float.
Console.WriteLine(10.0/7 - (1.0/9 + 2.0/63) * 10);
выдает 2,22044604925031E-16
Если я каким-то образом извернусь и сделаю свою VM, которая будет оперировать на long double, то ошибка будет ~1e-21
Вы забыли о первоначальной задаче. Всё-таки ,получается, может выйти так, что программа решит, что равенства нет, хотя число - целое. Так что надо испоьзовать сравнение по модулю как раз с этой самой точностью округления
узнать, целое ли число x (типа float/double) в общем случае очень сложно и для некоторых чисел невозможно.
Например, начиная с некоторого X все числа целые
Вообще-то нет.
В примере, я привел две записи одного и того же числа 10/7 - они не совпали.
Вывод одно и тоже число может быть представлено несколькими машинными числами.
> Это ни о чём не говорит. лишь о том, что арифметика этих представлений не совпадает с привычной нам
Это говорит о том, что аналитически равные числа - за счет разной записи - в машине могут быть представлены уже в другом виде.
Есть числа, которые невозможно записать напрямую в машинном виде, и они записываются косвенно через выражения - при этом в зависимости от выбранного выражения - одно и то же число в машине будет представлено по разному.
void zz(int d)
{
float f = (float)d;
if (f == (int)f)
{
...
}
}
сработает ВСЕГДА. Вообще всегда. Совсем всегда.
Все эти проверки (в том числе и та, которую я писал) на самом деле пытаются исправлять ошибки твоего Численного Метода.
Да, разные способы вычисления приближённых величин дадут разные результаты, тебя это удивляет? Однако значение float f = 1/3 детерминированно. Если ты в своём выражении в явном виде напишешь места, где происходит округление, то есть разнесёшь его на простые инструкции вида "переменная = переменная операция переменная", то всё что ты будешь получать на каждом этапе тоже будет жёстко детерминированно.
Я это уже в посте наверху сказал: все эти сравнения с эпсилоном - это исправление ошибок численного метода, и подходить к ним нужно именно с этой позиции.
не всегда, конечно.
float f = int.MaxValue;
Console.WriteLine(f == (int)f);
Выдает false
А это уже инт глючит =)
(float)int.MaxValue чуть больше чем int.MaxValue, поэтому когда её в инт обратно кастишь, получается отрицательное число. Вот. Я что-то об этом не подумал.
Оставить комментарий
t332
как? есть ли какая-нибудь функция!?