Проблемы с двойной точностью при увеличении
У меня есть этот алгоритм, который вычисляет значение Мандельброта точки (x0,y0) (x0 и y0 находятся где-то между -1 и 1, я думал, что не очень важно). Все идет очень хорошо, когда scale
не становится слишком большим, но при более высоких значениях scale
возвращенные значения очень неточные, и мой графический вывод начинает выглядеть странно. Как я могу предсказать, из какого значения scale
это происходит?
public static byte CalculateMandelbrot(double x0, double y0,double scale)
{
x0 /= scale;
y0 /= scale;
double y = 0;
double x = 0;
byte i = 0;
while (x * x + y * y < 4)
{
double tx = x;
x = x * x - y * y + x0;
y = 2 * tx * y + y0;
i++;
if (i == 0xFF) break;
}
return i;
}
2 ответа
Двойной имеет 53 бит точности. Это составляет около 16 знаков после запятой.
Если вы увеличите фрактал в 10^13 раз и получите изображение размером 1000x1000 пикселей, точность будет примерно равна разрешению экрана: минимальное возможное изменение в два раза - это шаг одного пикселя на экране.
Но до этого у вас будут проблемы, потому что вы повторяете итерацию формулы Мандельброта сто раз итеративно для одного и того же числа. Каждый расчет добавляет ошибку округления (несколько, вероятно) около 1/10^16. Можно (хотя и утомительно) предсказать, когда это станет заметным.
Внутренний блок FPU имеет большее число битов, чем стандартный double, это уменьшит вышеупомянутый эффект.
Это классическая ловушка "десятичный против двойного". Попробуйте использовать "десятичный" для всех переменных и посмотреть, если он щелкает.
Со справочной страницы C#:
По сравнению с типами с плавающей точкой, десятичный тип имеет большую точность и меньший диапазон
Существуют также реализации произвольной точности, такие как BigFloat Class.