Содержание
- Сложение и вычитание
- Умножение и деление
- Два слова о выловленном баге
- Как бороться?
- Увеличение разрядности
- Расстановка аргументов
- Разбиение сложных выражений на простые
- Подмена единиц измерения
- Контроль результатов
- Заключение
- Комментарии ( 14 )
- Главная > Документ
- Рекомендуем посмотреть:
В школе нам промывали мозги, заставляя несколько раз подряд произнести вслух, что от перестановки слагаемых сумма не изменяется.
Дело в том, что данное утверждение верно лишь тогда, когда речь идёт о конечном числе слагаемых. А вот попробуйте, к примеру, переставить члены условно сходящегося ряда, и сможете получить любую наперёд заданную сумму (в том числе и бесконечную)!
В школе всё упрощают, думая, что дети тупые и не поймут. На мой взгляд, школа отупляет детей, превращает их в безмозглое стадо. Лишь единицам удаётся пройдя сквозь этот ад остаться нормальными людьми.
С уважением,
Ян Альбертович Дененберг,
Назарет
А вот попробуйте, к примеру, переставить члены условно сходящегося ряда,
———–
Да. Из всех людей только Чак Норрис сумел досчитать до бесконечности. причем дважды.
Портал Проза.ру предоставляет авторам возможность свободной публикации своих литературных произведений в сети Интернет на основании пользовательского договора. Все авторские права на произведения принадлежат авторам и охраняются законом. Перепечатка произведений возможна только с согласия его автора, к которому вы можете обратиться на его авторской странице. Ответственность за тексты произведений авторы несут самостоятельно на основании правил публикации и законодательства Российской Федерации. Вы также можете посмотреть более подробную информацию о портале и связаться с администрацией.
Ежедневная аудитория портала Проза.ру – порядка 100 тысяч посетителей, которые в общей сумме просматривают более полумиллиона страниц по данным счетчика посещаемости, который расположен справа от этого текста. В каждой графе указано по две цифры: количество просмотров и количество посетителей.
© Все права принадлежат авторам, 2000-2019. Портал работает под эгидой Российского союза писателей. 18+
Выловив в программе заморского коллеги очередной баг, решил его описать, поскольку сталкиваюсь с такой ошибкой уже не в первый раз.
Простое правило арифметики, знакомое всем со школьной скамьи, приняло форму аксиомы. И если спросить у любого обывателя: «Есть ли разница в записях d=a-b+c и d=c+a–b?» — то, скорее всего, получим ответ, что записи тождественны. Однако, если такой же вопрос задать программисту, то в ответ услышим «Не всегда» или получим серию уточняющих вопросов. Плох тот программист, который скажет, что разницы в этих записях нет.
Сложение и вычитание
Свойство линейности арифметических операций сложения, вычитания и умножения справедливо только в теории. На практике при реализации этих операций силами АЛУ, мы зажаты некоторыми ограничениями, и в первую очередь – представлением чисел и их разрядностью.
Рассмотрим для начала простой пример:
После запуска программы получим «ERROR!». Почему так происходит? Для ответа на этот вопрос нужно знать две вещи:
При ненулевой экспоненте числа хранятся в нормированном виде, т.е. предполагается, что старший бит мантиссы всегда равен «1» (и фактически он в переменной отсутствует, а в мантиссе хранятся только младшие 23 бита). Такая форма записи позволяет хранить максимальное число значащих разрядов (т.е. хранить число с максимальной точностью).
При сложении и вычитании чисел с плавающей запятой сперва производится приведение к общему показателю степени. Проблема заключается в том, что при операциях над числами, разность между которыми (при одинаковом значении экспоненты) превышает размерность мантиссы, после приведения к общему показателю степени у меньшего числа происходит потеря значимости.
Рассмотрим наш случай:
Первое выражение: d = a – b + c;
Числа a и b представлены в памяти следующим образом:
(примечание: в скобке указана старшая единица, наличие которой подразумевается, но в переменной она не хранится)
А число c так:
При выполнении вычитания чисел a и b приведение не требуется, т.к. показатели степеней и так равны. Результат вычитания равен 0. Далее к результату прибавляется число c. Т.к. одно из слагаемых = 0, то приведение опять не требуется, и результат сложения будет равен 1, что, в общем-то, и ожидалось.
Читайте также: Как работает бензонасос на инжекторе
А вот со вторым выражением все не так: e = c + a – b.
Первым делом будет выполнена операция сложения чисел c и a, и т.к. они оба ненулевые и их экспоненты не равны, то требуется приведение показателя степени. Приведение всегда делается в большую сторону (оно и понятно: лучше потерять точность, избавившись от младших разрядов, чем значимость, избавившись от старших).
Экспонента числа c будет увеличиваться (с одновременным сдвигом мантиссы вправо) до тех пор, пока она не станет равной экспоненте числа a. В нашем случае мы имеем дело с экспонентами 10010111(bin) = 151(dec) и 01111111(bin)=127(dec). Видно, что экспоненту числа c нужно увеличить 151-127=24 раза. Столько же раз будет выполнен сдвиг мантиссы, а т.к. мантисса у нас 24-разрядная, то, что бы в ней ни находилось, после 24 сдвигов она станет равной нулю.
Таким образом, при сложении чисел c и a получим:
1.0 + 2.0e7 -> 0.0 + 20000000.0 = 2000000.0 = 2.0e7
Далее выполняется вычитание из результата числа b. Экспоненты их равны, поэтому приведение не требуется, а результат будет равен нулю.
Умножение и деление
В еще большей степени эта проблема касается выражений, содержащих несколько последовательных операций умножения и деления, т.к. тут она может возникнуть не только с вещественными числами, но и с целыми.
Результат первого выражения будет близок к ожидаемому (33.33), т.е. 33. А вот со вторым выражением произойдет следующее: результат целочисленного деления a на c будет равен 1 (при целочисленном делении дробная часть просто отбрасывается, и вместо 1.66(6) получим просто 1). Далее эта единица умножается на b и получится результат 20 (т.е. ошибка больше, чем на 50%).
Казалось бы, логично взять на вооружение правило записывать выражения так, чтобы сперва выполнялись умножения, а затем деления. Но рассмотрим пример 2:
В данном случае более близким к истине (6666.66(6)) будет именно второй результат: 200/6*200 = 33*2000 = 6600. А в первом выражении при умножении a на b произойдет переполнение: 200*200 = (40000) = -25536. Далее отрицательное число делится на 6 и получается -4256, т.е. совсем далеко от предполагаемого результата.
Два слова о выловленном баге
Программа была частью измерительно-вычислительного комплекса. Не вдаваясь в подробности, скажу, что среди прочего она вычисляла свойства газовой среды (воздуха), одним из которых был градиент температуры между точками измерения. В довольно большом количестве формул была формула с таким фрагментом:
Здесь t1 и t2 – вещественные числа, обозначающие времена процессов 1 и 2, выраженные в микросекундах, а 1.0 – компенсационная константа 1 мкс (какая-то поправка на конструктивные особенности прибора, на самом деле = 1.012…). Надо сказать, что времена t1 и t2 могли достигать нескольких секунд, и выраженные в микросекундах их значения могли достигать нескольких миллионов. В общем случае эти времена за одно измерение имели очень близкие значения, разница была не более сотен микросекунд.
Программист, записывая формулу в более, на его взгляд, красивом виде, изменил порядок аргументов:
Как это повлияло на работу программы? Именно так, как было описано в начале статьи. Константа 1.0 терялась (при приведении показателя степени) при значениях t1, больших или равных 2^24 (=16777216 мкс). И чем ближе друг к другу были значения переменных t1 и t2, тем больше сказывалось отсутствие компенсационной константы, поэтому чем стабильнее была среда, тем сильнее прибор врал.
Попутно программист совершил еще одну ошибку: когда значение переменной t1 оказывалось равным значению t2, в знаменателе получался 0. Отсюда – трап.
Как бороться?
Универсального решения для данных ситуаций нет. Но можно следовать нескольким советам.
Увеличение разрядности
Первое, что приходит на ум — увеличить разрядность переменных, если это возможно. Т.е. вместо float использовать double, вместо short использовать long. И в подавляющем большинстве случаев этого будет достаточно. Но есть небольшие ограничения. Помимо тех случаев, когда разрядность увеличивать уже некуда (например, используются 32-битные целые, а числа большей разрядности конкретный компилятор не поддерживает), этот способ ведет к увеличению расхода памяти и снижению скорости вычислений.
Расстановка аргументов
Желательно выполнять расстановку аргументов выражений в порядке, учитывающем область наиболее вероятных значений переменных с тем, чтобы снизить вероятность возникновения переполнений и потери значимости.
Применительно к описываемой программе можно было на этапе проектирования учесть особенности значений в переменных t1 и t2. Правильная расстановка переменных в выражении спасла бы ситуацию: t1-t2+1.0. В этом случае после первого вычитания получилось бы число одного порядка с константой 1.0, и потеря значимости не произошла бы.
Читайте также: Сколько литров бак на ваз 2107 карбюраторРазбиение сложных выражений на простые
При разбиении сложных выражений на несколько простых появляется возможность контролировать промежуточные результаты.
Применительно к описанной программе правильнее было сделать вычисление знаменателя до основных вычислений:
Теперь появилась возможность не только проверять знаменатель dt на 0, но также сделать предварительную проверку, не произойдет ли переполнение при делении на, хоть и ненулевое, но очень маленькое число.
Подмена единиц измерения
Иногда при вычислении больших формул есть смысл на каком-то этапе изменять единицы измерения некоторых величин, а по завершению вычислений делать коррекцию.
Например, одним из параметров расчета является частота, значение которой варьируется в пределах 100..1000 МГц, а другим — емкость конденсатора, значение которой варьируется в пределах 1пФ до 1мкФ. В переменных значения этих величин хранятся в явном виде, т.е. частота от 100000000.0 до 1000000000.0, а емкость от 0.000000000001 до 0.000001. В этом случае может оказаться удобным перевести значения переменных в другие единицы измерения с тем, чтобы в расчетах принимали участие числа примерно одного порядка. Частоту перевести, например, в мегагерцы, а емкость, например, в нанофарады. Тогда в вычислениях будут участвовать числа от 100.0 до 1000.0 и от 0.001 до 1000. По завершении вычислений нужно будет сделать поправку результата.
Контроль результатов
Никогда не вредно перепроверять расчеты вычислениями другим способом (например, производить их более грубым и более быстрым способом, который не даст нужной точности, но, по крайней мере, даст примерное ожидаемое значение) или просто проверять достоверность полученных результатов. Например, если вычисляем скорость звука в воздухе, то вряд ли правильно рассчитанное значение может отличаться на порядок от 344 м/с. Это, конечно, не убережет от возможного попадания в трап, но по крайней мере не выдаст пользователю кривой результат или, что было бы еще опаснее, не даст программе принимать решения по неверным результатам.
Заключение
- ошибки программирования
- +14
- 20 марта 2011, 23:43
- tester
Комментарии ( 14 )
Полезная статья.
А расчет с плавающей запятой — вообще забавная штука, подводных камней дофига. В первой программе например я сперва обратил внимание на строгое сравнение двух float’ов, что тоже не комильфо)
И насчет упрощенных расчетов. На АСКУ рассказывали забавный случай, когда приближенный алгоритм расчета выдавал гораздо более точный результат чем точный — он был намного короче и в точном накапливались ошибки округления float’ов.
Еще довольно частый пример, который наверняка многие видели. Устанавливается какая-то программа, прогресс ползет… ползет… ползет… доползает, например, процентов до 40 и сбрасывается на ноль Это как раз типичное переполнение в формуле progress = 100 * InstalledBytes / TotalBytes. При размере более примерно 20-40 МБ (в зависимости от знаковости переменных) происходило переполнение. Сразу разработчики инсталлера (а инсталлер крупный, то ли Wise, то ли Install Shield) не заметили — это были времена, когда 40 МБ было много Вот только потом эту версию часто юзали пираты… Для игрушек…
- Vga
- 21 марта 2011, 00:01
- ↓
Любой уважающий себя программист знает что вещественные числа сравнивать непосредственно нельзя, обязательна погрешность. И про округление чисел и переполнение знает не по наслышке. а фраза «Программист, записывая формулу в более, на его взгляд, красивом виде» вообще убила, что бы видя разность времени оставить её без скобок, тем более что время во вещественных переменных (на такое я полагал только борланд способен). Я говнокодер, но и то округления и приведения типов учитываю.
В целом статья отличная. Описаны довольно проблемные места.
Главная > Документ
Ведущий. Добрый вечер! Сегодня по традиции в нашей школе проводится интеллектуальная игра между сборной старшеклассников и командой учителей.
Можно очень много говорить о такой науке как математика, но лучше чем Паскаль не сказать «предмет математики настолько серьезен. Что полезно не упускать случая, сделать его немного занимательным».
Так пусть эта встреча будет и занимательной и познавательной. И кто бы сегодня не выиграл, победу над нашими сердцами одержит математика.
I . Представление команд.
а) команда учителей (приветствие)
Читайте также: Магнитола пионер не выключается с кнопки
б) команда старшеклассников (приветствие)
2. Представление магистров.
Вопросы для первой команды.
Родные братья параллелограмма.
Назовите автора вашего учебника по геометрии.
Сотая часть числа.
Знак операции извлечения арифметического корня.
Решето Эротосфена состоит из каких чисел?
Сколько нулей в миллионе?
А в двух миллионах?
Графиком какой функции является прямая?
Автор системы координат.
Автор книги по геометрии «Начало».
Основная геометрическая фигура.
Число на которое делят.
Часть прямой, заключенная между двумя точками.
Геометрическая фигура. Состоящая из трех точек не лежащих на одной прямой и трех отрезков по парно соединяющих эти точки.
Название закона «От перемены мест слагаемых сумма не меняется».
Вопросы для второй команды.
При какой температуре закипает морская вода?
Известный русский писатель, автор книги «Арифметика».
Единица измерения углов.
Назовите наименьшее трехзначное число.
Кто первый начал применять геометрию для обороны.
Что тяжелее: пуд пуха или пуд чугуна?
Определенная последовательность действий.
Инструмент для измерения углов.
Рассуждения при которых устанавливается истинность утверждения?
Луч, делящий угол на две равные части.
Сумма длин сторон.
Наибольшее сторона прямоугольного треугольника.
Результат сложения чисел.
Утверждение в геометрии не требующее доказательства.
Парабола график какой функции?
Название угла в 180 0
Параллелограмм у которого все стороны равны.
Назовите распределительное свойство умножения.
III . Основная игра.
Командам дается 2 минуты на обсуждение вопроса.
Остальные правила игры «Брейн-ринг».
В работе этих специалистов всегда мешают перемены.
Вопрос. Назовите их.
В переводе с греческого это слово означает «кегля», «сосновая шишка», «острие шлема». Соответствующий термин ввел Евклид.
Вопрос. О какой фигуре идет речь?
Он спас паром от катастрофы путем арифметической процедуры, доступной даже первокласснику.
Вопрос. Назовите его.
Когда к устам прильнут уста
Быть может голова пуста,
Но если вдруг четыре круга
Решат поцеловать друг друга,
То лишь геометра расчет
Их к поцелую приведет.
Вариантов два любой не плох.
Это стихотворение принадлежит известному английскому химику Фредерико Садди и было опубликовано в 1934 году.
Вопрос. За две минуты нарисуйте четыре окружности, которые одновременно касаются друг друга.
В переводе с греческого это слово означает игральная кость. Такая кость имела определенную форму и название перешло на любое тело той же формы. В частность – это котел для кипячения жидкости, варки и т.д.; в общежитиях обычно так называют комнаты определенного назначения.
Вопрос. О какой фигуре идет речь?
Попрыгунья Стрекоза половину времени каждых суток спала, 1/3 – танцевала, шестую часть она решила посвятить подготовке к зиме.
Вопрос. Сколько часов в сутки Стрекоза готовилась к зиме?
В одной сказке хозяин, нанимая работника, предложил ему следующее испытание – наполнить водой бочку ровно на половину, ни больше ни меньше, но ничем для измерения не пользоваться. Работник справился с заданием. Вопрос. Как?
Представьте, что вы основательница легендарного Карфогена – финикийская царица Дидона, выторговали у вождей африканских племен, населявших север Африки, право владеть клочком земли, которой покроет воловья шкура. Решив при этом задачу о том, какую форму должна иметь фигура, чтобы ограниченная ею площадь была максимальной.
Вопрос. Как это сделать? Назовите эту фигуру?
Вопрос. Назовите науку за успехи в которой Нобелевская премия не присуждается?
Один из афоризмов Козьмы Пруткова гласит: «Бросая в воду камешки смотрите на круги ими образуемые, иначе такое бросание будет пустой забавой». Это высказывание родилось на берегу пруда со стоячей водой.
Вопрос. Как меняется форма воды, если камешки бросать в речку?
Этот ударный музыкальный инструмент многим напоминает теорему Пифагора?
Вопрос. Назовите этот инструмент.
Окружность не только является совершенной кривой, как считали древние греки, но и той кривой, по которой блуждает человек в тех местах, где нет возможности ориентироваться.
Вопрос. Почему человек блуждает по окружности?
Подведение итогов игры. Вручение призов.
Подошла к концу наша встреча. И мне хочется пожелать вам. Чтобы математика заняла достойное место в вашей жизни. Ибо как сказал Дарвин: «У людей усвоивших велики принципы математики, одним органом чувств больше, чем у простых смертных». До новых встреч.
Источник: