Вот суть вашей путаницы:
В связи с плавающей точкой представление точность, это может быть что-то как 122.99999999999999999999 или 123.000000000000000000001.
Это неверно. Он всегда будет ровно 123 на совместимой с IEEE-754 системе, которая почти все системы в эти современные времена. Арифметика с плавающей точкой не имеет «случайной ошибки» или «шума». Он имеет точное, детерминированное округление, и многие простые вычисления (например, этот) вообще не требуют округления.
123
точно представима в плавающей точкой, и поэтому 123*123
(поэтому они все целые числа скромных размеров). Таким образом, ошибка округления не возникает при преобразовании 123*123
в тип с плавающей запятой. Результат точно15129
.
Квадратный корень правильно округленный операция по стандарту IEEE-754. Это означает, что если есть точный ответ, для его создания требуется функция квадратного корня. Так как вы извлекая квадратный корень точно15129
, который точно123
, это точно результат, который вы получите от функции квадратного корня. Не происходит округления или аппроксимации.
Теперь, насколько велика целое число, это будет верно?
Двойная точность может точно представлять все целые числа до 2^53. До тех пор, пока i*i
будет меньше 2^53, округление не произойдет при вычислении, и результат будет точным по этой причине. Это означает, что для всех i
меньше 94906265
, мы знаем, что вычисление будет точным.
Но вы пробовали i
больше! Что происходит?
Для самых больших i
что вы пытаетесь, i*i
всего лишь 2^53 (1.1102... * 2^53
, фактически). Поскольку преобразования из целого числа в двойное (или умножение в двойном) также являются правильно округленным операций, i*i
будет представляемым значением, ближайшим к точному квадрату i
. В этом случае, поскольку i*i
имеет ширину 54 бита, округление произойдет в самом нижнем разряде. Таким образом, мы знаем, что:
i*i as a double = the exact value of i*i + rounding
где либо -1,0, or 1
. Если округление равно нулю, то квадрат является точным, поэтому квадратный корень является точным, поэтому мы уже знаем, что вы получите правильный ответ. Давайте проигнорируем этот случай.
Итак, теперь мы смотрим на квадратный корень i*i +/- 1
. Используя разложение в ряд Тейлора, бесконечно точное (неокругленное) значение этого квадратного корня:
i * (1 +/- 1/(2i^2) + O(1/i^4))
Теперь это немного неудобным, чтобы увидеть, если вы еще не сделали какого-либо анализа ошибок с плавающей точкой и раньше, но если вы использовать тот факт, что i^2 > 2^53
, вы можете увидеть, что: термин
1/(2i^2) + O(1/i^4)
меньше 2^-54, что означает, что (так как квадратный корень правильно округлый, и, следовательно, его ошибка округления должна быть меньше, чем 2^54), округленный Результатом функции sqrt является точно i
.
Оказывается, что (с аналогичным анализом) для любого точно представляемого числа с плавающей запятой x, sqrt (x * x) является ровно x (при условии, что промежуточный расчет x*x
не переполнен или нисходит) поэтому единственный способ, которым вы можете столкнуться при округлении для этого типа вычислений, находится в представлении самого x
, поэтому вы видите его начиная с 2^53 + 1
(наименьшее непредставимое целое число).
Вы можете изменить 'i = 0; 100000000.times {puts i; i + = 1} '' 100000000.times {| i | ставит i} ' –
вправо, спасибо. его немного проще теперь – martinus