#1 28.02.06 17:32
Мистика в вычислениях
почему-то билдер в любом раскладе при вычислении такого выражения дает такой результат:
426.6432 - (int)426.6432 = 0.643200000000014
числа произвольные написал, но смысл думаю ясен
задача вообще-то по моделированию. требуется получить последовательность СЧ с помощью датчика Лемера
при любой точности (хоть float, хоть long double) последовательность зануляется на 8-й - 10-й итерации, как-будто комп сам подбирает нужные числа...
а вот выражение для датчика Лемера:
X[i+1] = X[i]*3456 - (int) (X[i]*3456)
X[0] = 0.12345 (можно в принципе и 0.123456789 взять)
потратил вчера на это 3 часа и не понял откуда эти лишние 0,000000000000014 берутся
а вот и код:
double X[100];
memset(X, 0, sizeof(X));
X[0] = 0.12345;
ListBox1->Items->Add(X[0]);
for (int i = 1; i < 100; i++)
{
X[i] = X[i-1]*3456.0 - (int) (X[i-1]*3456.0);
ListBox1->Items->Add(X[i]);
}
Offline
#2 28.02.06 18:11
Re: Мистика в вычислениях
а это проблемма хранения данных типа float, ты посмотри как он хранится и все станет ясно...я про число, експоненту..и что там еще было подзабыл))
Offline
#4 28.02.06 20:09
Re: Мистика в вычислениях
гыы.... это такой прикол у Билдера есть... я в свое вермя его тоже обнаруживал... ничего с этой ошибкой не поделаешь, ошибка она просто появляется и все. Причем проявляется она в последних 2-х разрядах (переходит ли на 3-й с конца - помню)....
даже если в Билдере просто взять вот такой вот код:
Код::
double A = 1; for(int i = 0; i < 1000 ;i++) A+=1;
То высока вероятность, что А после цикла не будет равняться 1001.....
Избежать эту ошибку (по крайней мере, я больше ни в каких случаях этой ошибки не встречал) можно уходом от последовательного складывания double в цикле к умножению на какой-то множитель....
Offline
#6 28.02.06 21:36
Re: Мистика в вычислениях
Хм... а если мутить проект не в билдере, ошибка не появится? Или это все-таки связано именно с хранением чисел с плавающей точкой?
и кстати если поставить где-нибудь брейкпойнт в проекте и в watchlist'е написать что-нибудь типа 426.1-426, то результат, как говорится, налицо :)
и даже без всяких циклов...
и почему-то эта незначительная ошибка с огромной точностью сводит ряд СЧ к нулю :)
Offline
#7 28.02.06 22:16
Re: Мистика в вычислениях
simplex,
simplex написал(а):
а если мутить проект не в билдере, ошибка не появится?
скорее всего появится. В любом нормальном учебнике по программированию указано, что нельзя напрямую сравнивать 2 вещественных числа...
в этом примере - юзай целочисленные типы как числа с фиксированной точкой. Плавающая тебе здесь не нужна...
Если long будет не достаточно (19 разрядов), то определи свой тип, более длинный...
В VS.NET есть тип Currency, он хранит 96 бит числа....
Offline
#10 01.03.06 01:44
#11 06.03.06 01:28
Re: Мистика в вычислениях
целочисленные переменные хранятся в памяти в двоичном виде: x0*2^0+x1*2^1+x3*2^2+x4*2^3. причем, число это x4x3x2x1x0 (двоичный вид). Дробные числа хранятся по-другому: x0*1/2^1+x1*1/2^2+x2*1/2^3+x3*1/2^4.... т.е. последовательным суммированием дробей. В итоге получается, что никогда не получить точного значения 0.32413245 - будет лишь приближение 0.32413245111111 (к примеру). Приводя целое к дробному получаем, такое, что появляется некоторый хвост, от которого не избавиться никогда. Выход - округление до нужного разряда после вычислений.
Offline
#12 07.03.06 09:19
#13 14.03.06 08:24
Re: Мистика в вычислениях
Да с хранением уже все ясно... Теперь мучает другой вопрос: есть тип Currency (с фиксированной точкой, 4 разряда в дробной части). Если эта точность меня не устраивает и мне надо 8, то, как уже советовали, можно описать свой тип данных наподобие Currency. Как это сделать? Примерчик кинули бы... или ссылочку
Offline

