if (b1 != o1)
{
test << "1 : " << o1 << "," << b1 << endl;
}
В ответ получаем
1 : 125.21,125.21
Преобразование типа не помогает
if ( (int(1000*b1)) != (int(1000*o1)) )
Проблема в том, что с o1 и b1 в программе проводится куча вычислений
все это находится в цикле и выскакивает далеко не сразу,
поэтому я и анализирую именно текстовый файл.
Какие могут быть причины возникновения такого глюка?
Как в диагностических целях вывести значение переменных в тестовый файл, чтобы этот глюк можно было отловить?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Анатолий Широков, Вы писали:
АШ>>А ты сравнивай на равенство с заданной точностью.
А>А как это сделать?
А>Это я понимаю. А>А почему такая фигня может происходить?
Проблема в том, что мощность множества вещественных чисел равна бесконечности, поэтому только узкое подмножество вещественных чисел представимо в памяти машины точно.
А>Что же теперь при каждой проверке на равенсво это использовать?
Здравствуйте, <Аноним>, Вы писали:
А>Что же теперь при каждой проверке на равенсво это использовать?
Ну, как вариант, напсать арифметику для чисел с фиксированой точкой и работать с ними (я таким как-то занимался, деньги считал). Там все проще: чего сказал, то и будет =)
Здравствуйте, ssm, Вы писали:
ssm>Здравствуйте, LuciferMoscow, Вы писали:
LM>>Кто же тебя так учил double сравнивать? LM>>a-b < eps, где eps маленькое 1e-8
ssm>а тебя хто так учил? ssm>по модулю, батенька, по модулю... ssm>
ну и на старуху....
Re[7]: Помогите! Я тут с ума уже схожу с !=
От:
Аноним
Дата:
30.03.05 15:02
Оценка:
АШ>Проблема в том, что мощность множества вещественных чисел равна бесконечности, поэтому только узкое подмножество вещественных чисел представимо в памяти машины точно.
О! Я слово мощность в этом контексте не слышал с момент окончания мат. анализа в институте, но помню, что оно значит.
Все это я понимаю.
Я не понимаю, где конкретно возникает (может возникать) ошибка и как это место отловить?
А>>Что же теперь при каждой проверке на равенсво это использовать?
АШ>При каждой.
А если все числа в моей программе будут ограничены по количеству знаков двумя знаками после запятой и умножения/деления я не буду проводить, тогда можно пользоваться ==(!=)?
Здравствуйте, Аноним, Вы писали:
АШ>>Проблема в том, что мощность множества вещественных чисел равна бесконечности, поэтому только узкое подмножество вещественных чисел представимо в памяти машины точно.
А>О! Я слово мощность в этом контексте не слышал с момент окончания мат. анализа в институте, но помню, что оно значит.
Можно было сказать проще: "вещественных чисел бесконечно много", но с "мощностью" звучит заметно авторитетнее=))
А>О! Я слово мощность в этом контексте не слышал с момент окончания мат. анализа в институте, но помню, что оно значит. А>Все это я понимаю. А>Я не понимаю, где конкретно возникает (может возникать) ошибка и как это место отловить?
Конечно, в результате вычислений.
А>>>Что же теперь при каждой проверке на равенсво это использовать?
АШ>>При каждой.
А>А если все числа в моей программе будут ограничены по количеству знаков двумя знаками после запятой и умножения/деления я не буду проводить, тогда можно пользоваться ==(!=)?
Здесь важно не два знака после запятой, а важно другое — могут ли они быть представлены точно числами с плавающей запятой. Если могут, то сравнивайте.
Здравствуйте, Аноним, Вы писали:
А>А если все числа в моей программе будут ограничены по количеству знаков двумя знаками после запятой и умножения/деления я не буду проводить, тогда можно пользоваться ==(!=)?
Двумя знаками в какой системе счисления? Если в десятичной, то это бесперспективняк: конечные десятичные дроби — периодические двоичные.
Конечно, можно каждый результат вычислений сразу округлять — хоть до двух десятичных знаков, хоть до чего угодно. То есть, работать с ещё меньшим подмножеством вещественных чисел, чем double.
Только из-за этого ошибки вычислений будут расти ещё стремительнее.
Ведь откуда возникают неравенства:
Есть две функции над вещественными числами: f(x), g(x), причём известно, что f(x0)==g(x0).
Переходя к числам конечной точности (плавающим или фиксированным — неважно), мы вводим ошибку: X0 = R(x0) = x0+dx.
При этом уже не факт, что f(X0)==g(X0).
(x,f,g — точные значения и функции, X,F,G — вычислимые).
Далее, вычисляя эти функции, мы к этой погрешности добавляем разнообразные ошибки, связанные с конечной разрядной сеткой и конечным временем вычислений. Поскольку формулы f и g разные, то результирущие отклонения от ожидаемого
значения, df = F(X0)-R(f(X0)), dg = G(X0)-R(g(X0)) — будут разными.
Поэтому, F(X0)!=G(X0), хотя f(x0)==g(x0).
Однако, можно оценить погрешность вычислений — то есть, максимальный разброс df и dg.
Если eps = max(|df|+|dg|) на некотором множестве x, то |F(X0)-G(X0)| <= eps.
Ну и, кроме прочего, есть вычисления, дающие бОльшие и меньшие ошибки.
Наверное, самый известный пример: суммирование множества чисел с плавающей запятой.
Две основных беды — это ошибки денормализации и нормализации. На плохом наборе (сначала складываем очень большие числа, потом очень маленькие) это может привести к изумительным результатам:
1 + 0.00000000000001{*10000000000000} == 1.
Суммирование по Хаффману (вынимаем два самых маленьких по модулю числа, складываем, возвращаем результат в набор) минимизирует эту засаду.
Warturtle пишет:
> АШ>>Проблема в том, что мощность множества вещественных чисел равна > бесконечности, поэтому только узкое подмножество вещественных чисел > представимо в памяти машины точно. > А>О! Я слово мощность в этом контексте не слышал с момент окончания > мат. анализа в институте, но помню, что оно значит. > Можно было сказать проще: "вещественных чисел бесконечно много", но с > "мощностью" звучит заметно авторитетнее=))
Еще авторитетнее: "мощность множества вещественных чисел равна алеф-1"