Является ли «ошибка калькулятора» проблемой кода? - PullRequest
2 голосов
/ 13 декабря 2010

Я видел эту ошибку во многих сообщениях в блоге: http://atifsiddiqui.blogspot.com/2010/11/windows-calculator-bug.html

Является ли эта ошибка ошибкой кода или математической неточностью?

Мне интересно, действительно ли это ошибка, как она не обнаруживалась годами?

Что я должен позаботиться о том, чтобы этого не произошло в моей программе caculator.*

Ответы [ 7 ]

6 голосов
/ 13 декабря 2010

Да, это ошибка.Тот факт, что у него есть техническое объяснение (которое вряд ли приемлемо для непрофессионала), не освобождает его от ошибки.Если это не ошибка, то вы либо утверждаете, что - как мы все иногда делаем - «это особенность», либо что это ограничение системы.

Чтобы устранить ее, я бы предложил вам обойтикаждый результат до приемлемого уровня точности, чтобы удалить очень маленькую ошибку.Как показывают другие ответы, проблема в том, что в вашем калькуляторе квадратный корень из «4» - это не «2», а число, очень близкое к 2. Чтобы разрешить этот раунд, получим 10, 20, 30 десятичных знаков иливсе, что вы можете себе позволить.

Я бы сказал, что любой механизм калькулятора должен иметь базовый уровень точности, превышающий доступный уровень точности с достаточно большим запасом, чтобы пользователь не мог получить доступ к пределамарифметика с плавающей точкой.Если вы выберете этот путь, вы потеряете одну форму «точности», но просто заявите, что ваш калькулятор имеет точность до n десятичных знаков.Это более чем приемлемо, особенно если это решит эту проблему.

Однако это не так уж важно, не так ли?


Как-то так, я однажды работал над финансовым приложением,Вендор предоставил некоторое программное обеспечение, которое должно было рассчитать некоторые сложные процентные ставки.Их расчеты всегда были выключены.Они утверждали, что это было «из-за арифметики с плавающей точкой» и пытались обучить меня этому вопросу;но их алгоритм был далеко.При составлении процентных ставок для сумм в долларах мы всегда округляем итоговую сумму после каждой итерации (день, неделя, месяц, год или что-либо еще).В зависимости от ситуации он может округляться до ближайшего доллара, ближайшего цента или ближайшей сотой доли цента, но это количественно, и мы никогда не составляем миллионные доли процента из года в год.Это подход, который вам следует использовать, если вы хотите избежать ошибки округления вычислений.

3 голосов
/ 13 декабря 2010

Я согласен с @Kirk Broadhurst, что это технически ошибка, так как результат sqrt (4) -2 строго равен 0, а Calc дает другой (хотя и очень близкий) результат. Тот факт, что обычно мы можем жить с этой неточностью, здесь не имеет значения. Строго говоря, программисты должны были искать разные подходы для решения подобных проблем.

ИМХО, многие люди здесь не видят, что 4 и 2 точно представлены в формате IEEE с плавающей запятой. Наличие естественной степени 2 делает его представимым с бесконечной точностью, поэтому аргументы, обвиняющие формат FP, также не имеют значения. Проблема заключается в алгоритме функции sqrt (), а не в формате хранилища FP.

3 голосов
/ 13 декабря 2010

Как уже говорили другие, это не ошибка, а связано с тем, как компьютеры представляют числа с плавающей запятой внутри себя и обрабатывают арифметику с плавающей запятой. Оказывается, мы с вами не думаем вматематика с плавающей точкой, но компьютеры делают.И эта «плавающая точка» относится к двоичной точке, а не к десятичной.

Числовое значение, которое она возвращает, на самом деле чрезвычайно близко к 0 (что, я думаю, мы можем всесогласен, это "правильный" десятичный ответ).Случилось так, что сама функция sqrt вернула число чрезвычайно , близкое к 2, но это число не может быть сохранено внутри как точно два из-за ограничений типа с плавающей запятой. output был числом «2», потому что Calculator просто округлил его для целей отображения, зная, что «2» был ответом, который вы ожидали.Но затем, когда вы вычитаете 2 из этого внутренне сохраненного представления sqrt(4), вы не получаете точно 0, потому что число, хранимое внутри, не было точно 2.

Каждый программист должен действительно прочитать "ЧтоКаждый учёный-компьютерщик должен знать об арифметике с плавающей точкой ", которая объясняет это поведение (в частности, разделы" Точность "и" Двоичное-десятичное преобразование ") и множество других ошеломляющих деталей о том, как компьютеры представляютвнутренние числа как типы с плавающей запятой.

2 голосов
/ 13 декабря 2010

Это общая проблема с плавающей точкой.Если вы возьмете, например, 1/3 aqnd, а затем умножьте на 3 в плавающей точке, вы получите не 1 назад, а 0.9999999999999999999999 или 1.000000000000000000001.Windows-калькулятор использовал некоторый алгоритм, чтобы попытаться свести к минимуму случаи, как я только что объяснил, но, возможно, они не обрабатывали все особые случаи ...

Это не совсем ошибка, скорее проблема юзабилитикак они обрабатывают некоторые случаи, но не все ..

1 голос
/ 13 декабря 2010

Это немного сложнее, чем обычные вопросы с плавающей запятой, так как calc на самом деле использует математику произвольной точности. Однако, как это ни странно, кажется, что для основных операций используется только бесконечная точность, как указано Реймонд Чен

Сегодня внутренние вычисления Calc выполняются с бесконечной точностью для базовых операций (сложение, вычитание, умножение, деление) и с точностью до 32 цифр для сложных операций (квадратный корень, трансцендентные операторы).

так что, предположительно, квадратный корень на самом деле приводит к значению, очень близкому, но не к 2, но которое отображается как 2, после точного вычитания у вас остается очень близкое к 0 число, которое не отображается как 0, хотя ошибка? зависит.

1 голос
/ 13 декабря 2010

Это , а не ошибка (компьютеры работают таким образом!). В SO много вопросов на эту тему. Например, выполните поиск "JavaScript math broken".

Опытный пользователь компьютера также должен понимать, что -8.1648465955514287168521180122928e-39 практически равен нулю.

Если вы хотите избежать подобных вещей, вы можете округлить каждый результат при преобразовании его в строку. -8.1648465955514287168521180122928e-39 будет округлено до 0. Это, однако, не работает, если вы пишете очень продвинутый калькулятор, способный работать, например, с константой Планка (если вы это сделаете, константа Планка будет считаться равной нулю , что плохо). Очень хорошая альтернатива - работать с символической математикой, но тогда калькулятор не займет минут, а месяцы / годы ...

0 голосов
/ 13 декабря 2010

С чистым предположением, я бы сказал, это потому, что калькулятор не получает точно 2 в результате квадратного корня (в зависимости от того, как он вычисляет корень). Но когда результат не равен нулю, он просто округляет дисплей. Но когда число близко к нулю, оно показывает точный результат.

Для собственного калькулятора вы, вероятно, не получите такие результаты, просто не имея такой высокой точности (чего обычно нет при использовании normal математических функций, которые дает язык программирования). 1006 *

...