Как компьютеры «Аполлон» оценивали трансцендентные функции, такие как синус, арктангенс, логарифм?

Навигация с помощью секстанта или маневры с использованием углов подвеса могут быть двумя примерами случаев, когда компьютеру Apollo может потребоваться выполнить тригонометрию.

Тригонометрические функции, такие как синус, арктангенс и т. д., трансцендентны , как и логарифмы. Вы не можете вычислить эти функции с помощью простого выражения, построенного, например, на умножении или делении, по крайней мере, без итеративного алгоритма.

Инженер на земле брал бы логарифмическую линейку для двух или трех цифр, а для большего количества цифр обращался бы к книге триггеров, логарифмических и других таблиц. Между двумя строками вы можете интерполировать вручную еще больше цифр.

Но как компьютеры «Аполлон» оценивали трансцендентные функции или, по крайней мере, как были реализованы в программах расчеты, требующие использования трансцендентных функций?

Вы уверены в необходимости тригонометрии для карданного подвеса? Я почти уверен, что было бы легче оставаться в рамках векторной математики, если бы вы использовали линейный привод. В любом случае тригнонометрические функции обычно реализуются путем поиска в таблице или аппроксимируются как разложение Тейлора . Нет источника, непосредственно связанного с Аполлоном, извините.
... или и то, и другое, расширение Тейлора, подготавливающее таблицы поиска при запуске, на случай, если постоянное хранилище меньше, чем ОЗУ.
@Christoph Первое предложение начинается с двух инструментов, которые, вероятно, производят угловые данные. Кроме того, то, что было сделано в 1960-х годах на компьютерах в космосе, не охвачено тем, как это делается сейчас. Я добавлю historyтег, чтобы сделать это еще яснее. Вы также можете подумать о том, где должны храниться таблицы, поскольку в компьютерах Apollo было очень мало памяти.
@Christoph, посмотрите здесь: youtu.be/9YA7X5we8ng?t=1283, а также здесь youtu.be/YIBhPsyYCiM?t=273
@Christoph: Уже в 1956 году у нас был алгоритм лучше, чем у Тейлора, а именно CORDIC. Я не знаю, использовалось ли это в Аполлоне.
Хранилище (как постоянное, так и динамическое) было в большом почете, поэтому неудивительно, что они не держали таблицу.
Тот же самый вопрос можно задать, например, калькуляторам или вообще любому компьютеру.
@Joshua считает, что они были разработаны в начале 1960-х годов. а также учитывая ограничения по размеру и весу для посадки на Луну и возвращения на Землю, это не просто «любой компьютер». Фактически, технологии, разработанные для компьютеров в рамках космической программы, помогли проложить путь к «персональным» научным калькуляторам десятилетие спустя. Именно совокупность ситуации делает этот конкретный вопрос неотразимым.
@MSalters: CORDIC нужны таблицы констант, около 50 значений. Не очень полезно для компьютеров Apollo с основной памятью для программы и констант.
@uhoh, я согласен, что ситуация в целом убедительна, но суть ответа (расширения Тейлора) такая же, как если бы я спросил, как это делает мой компьютер, по крайней мере, как я понимаю, что эти расчеты происходят сегодня.
@Joshua, хотя современные реализации могут включать одно или несколько расширений Тейлора в качестве семени (в зависимости от того, какая функция, грех легко найти здесь ), это только начало того, как современные компьютеры выполняют трансцендентальные вычисления с двойной точностью. Что я узнал из этого ответа, так это то, как именно это было сделано в этом случае, степень результирующей точности (~ 1E-04), с которой им пришлось работать, усилия, затраченные на предварительное и после масштабирование, и почему, а также спартанский кодирование.
@Joshua, все они уникальны для определенного набора ограничений на этом конкретном, единственном (несколько) в своем роде компьютере. На ваше редукционистское использование «то же самое, что и» единственное, что я могу сказать, это «нет, это не так», на что вы могли бы ответить «да, это так», и мы могли бы продолжать до бесконечности.
@Joshua точно - каждый цифровой компьютер делает это этим или подобными методами. Другой способ посмотреть на это: «Откуда взялись таблицы в книгах, в которых мы искали этот материал?» В прежние времена каким-то бедолагам приходилось перемалывать эти ряды вручную, а позже и с помощью механических калькуляторов, умевших умножать и делить. Общая область исследований называется «Численные методы», и вы можете легко найти множество книг под этим заголовком.
@Uwe на самом деле CORDIC был разработан специально для цифровых навигационных компьютеров в самолетах в 1956 году.
для журнала можно даже вывести значение на аналоговый компьютер, вычислить его и прочитать результат обратно в АЦП. Эти вещи можно сделать очень быстро в электрическом аналоговом компьютере. Я не знаю, работает ли он с тригонометрией, но механический аналоговый компьютер может это сделать, хотя и медленнее.
@Cris Straton: Из Википедии : «когда доступен аппаратный множитель (например, в микропроцессоре DSP), методы поиска в таблице и ряды мощности обычно быстрее, чем CORDIC». У компьютера Apollo было довольно быстрое умножение, время цикла памяти: 11,7 микросекунды. Время добавления: 23,4 микросекунды. Время умножения: 46,8 микросекунд.
@phuclv: в то время существовали аналоговые электронные схемы для логарифмирования, возведения в степень, сложения, умножения и квадратного корня, но не для тригонометрических функций, таких как sin, cos и tan.

Ответы (3)

Поскольку код Аполлона-11 находится на GitHub, мне удалось найти код, который выглядит как реализация функций синуса и косинуса: здесь командный модуль и здесь лунный посадочный модуль (похоже, это один и тот же код).

Для удобства привожу копию кода:

 # Page 1102
            BLOCK   02

# SINGLE PRECISION SINE AND COSINE

            COUNT*  $$/INTER
SPCOS       AD      HALF            # ARGUMENTS SCALED AT PI
SPSIN       TS      TEMK
            TCF     SPT
            CS      TEMK
SPT         DOUBLE
            TS      TEMK
            TCF     POLLEY
            XCH     TEMK
            INDEX   TEMK
            AD      LIMITS
            COM
            AD      TEMK
            TS      TEMK
            TCF     POLLEY
            TCF     ARG90
POLLEY      EXTEND
            MP      TEMK
            TS      SQ
            EXTEND
            MP      C5/2
            AD      C3/2
            EXTEND
            MP      SQ
            AD      C1/2
            EXTEND
            MP      TEMK
            DDOUBL
            TS      TEMK
            TC      Q
ARG90       INDEX   A
            CS      LIMITS
            TC      Q       # RESULT SCALED AT 1.

Комментарий

# SINGLE PRECISION SINE AND COSINE

указывает, что следующее действительно является реализацией функций синуса и косинуса.

Информацию о типе используемого ассемблера можно найти в Википедии .

Частичное объяснение кода:

Подпрограмма SPSINфактически вычисляет грех ( π Икс ) , и SPCOSвычисляет потому что ( π Икс ) .

Подпрограмма SPCOSсначала добавляет половину ко входу, а затем переходит к вычислению синуса (это верно из-за потому что ( π Икс ) знак равно грех ( π ( Икс + 1 2 ) ) ). Аргумент удваивается в начале SPTподпрограммы. Поэтому теперь нам нужно вычислить грех ( π 2 у ) за у знак равно 2 Икс .

Подпрограмма POLLEYвычисляет почти полиномиальную аппроксимацию Тейлора грех ( π 2 Икс ) . Во-первых, мы храним Икс 2 в регистре SQ (где Икс обозначает вход). Это используется для вычисления многочлена

( ( ( С 5 / 2 Икс 2 ) + С 3 / 2 ) Икс 2 + С 1 / 2 ) Икс .
Значения констант можно найти в том же репозитории GitHub .

С 5 / 2 знак равно .0363551 ( π 2 ) 5 1 2 5 ! С 3 / 2 знак равно .3216147 ( π 2 ) 3 1 2 3 ! С 1 / 2 знак равно .7853134 π 2 1 2

которые выглядят как первые коэффициенты Тейлора для функции 1 2 грех ( π 2 Икс ) .

Эти значения не являются точными! Так что это полиномиальное приближение, которое очень близко к приближению Тейлора, но даже лучше (см. ниже, также благодаря @uhoh и @zch).

Наконец, команда удваивает результат DDOUBL, и подпрограмма POLLEYвозвращает приближение к грех ( π 2 Икс ) .

Что касается масштабирования (сначала вдвое, затем вдвое, ...), @Christopher упомянул в комментариях, что 16-битное число с фиксированной точкой может хранить только значения от -1 до +1. Поэтому необходимо масштабирование. См. здесь источник и дополнительные сведения о представлении данных. Подробности инструкций по ассемблеру можно найти на той же странице.

Насколько точно это почти Тейлоровское приближение? Здесь вы можете увидеть график на WolframAlpha для синуса, и он выглядит как хорошее приближение для Икс от 0,6 к + .6 . Здесь показана функция косинуса и ее аппроксимация . (Надеюсь, им никогда не приходилось вычислять косинус для значения π 2 , потому что тогда ошибка была бы неприятно большой.)

@uhoh написал код на Python , который сравнивает коэффициенты С 1 / 2 , С 3 / 2 , С 5 / 2 из кода Аполлона с коэффициентами Тейлора и вычисляет оптимальные коэффициенты (исходя из максимальной ошибки для π 2 Икс π 2 и квадратичная ошибка в этой области). Это показывает, что коэффициенты Аполлона ближе к оптимальным коэффициентам, чем коэффициенты Тейлора.

На этом графике различия между грех ( π Икс ) и отображаются приближения (Аполлон/Тейлор). Видно, что приближение Тейлора гораздо хуже для Икс .3 , но гораздо лучше для Икс .1 . С математической точки зрения это не является большой неожиданностью, потому что тейлоровские приближения определяются только локально и, следовательно, часто полезны только вблизи одной точки (здесь Икс знак равно 0 ).

Обратите внимание, что для этой полиномиальной аппроксимации вам нужно всего четыре умножения и два сложения ( MPи ADв коде). Для управляющего компьютера Apollo циклы памяти и процессора были доступны только в небольшом количестве.

Есть несколько способов повысить точность и диапазон ввода, которые были бы доступны для них, но это привело бы к большему количеству кода и большему времени вычислений. Например, использование симметрии и периодичности синуса и косинуса, использование разложения Тейлора для косинуса или просто добавление дополнительных членов разложения Тейлора повысило бы точность, а также позволило бы использовать произвольно большие входные значения.

Я читаю об этом, но это нелегко, потому что я не знаком с языком программирования. На первый взгляд это похоже на тейлоровское приближение, но я не уверен. Я отредактирую, когда у меня будет больше.
Я в этом... я думаю, что это связано с масштабированием.
Масштабирование связано с тем, что одинарная точность может хранить значение только от -1 до +1 :). Точность составляет около 13 бит, что соответствует типу с одинарной точностью (16 бит, один из которых является битом знака, а один — битом четности, недоступным для программного обеспечения).
О господи... Я не видел ассемблера со времен колледжа, я не могу представить, что мне придется писать целый управляющий компьютер, используя только OP-коды и низкоуровневые функции. Также добро пожаловать в SE, блестящий ответ.
@Christoph Итак, я предполагаю, что это было представление с фиксированной запятой, а не с плавающей запятой, верно? Кроме того, у вас есть ссылка, которую я могу добавить к ответу (или вы можете отредактировать)?
@uhoh: проблемы с масштабированием теперь исправлены, и я включил графики для сравнения функции с приближением. Кажется, он подходит для некоторых значений.
Я нашел эту информацию в Руководстве программиста Virtual AGC .
По теме: график ошибок . Максимальная ошибка в домене будет около 0,0001.
@supinf О, я все время наблюдал за развитием твоего ответа. Альфа-ссылка Wolfram также полезна для понимания масштабов до и после масштабирования. Отличный анализ математики и кода!
@MagicOctopusUrn Большинство людей тоже. За исключением людей, которые делают это для развлечения, ASM сегодня более или менее ограничен обратным проектированием, людьми, занимающимися компиляторами, и своего рода встраиваемыми платформами со сверхнизкой стоимостью/возможностями/производительностью, где работа настолько же EE, как и CS.
Что еще приятно, он особенно точен вблизи (часто используемых) 0, 30 и 60 градусов.
Отличный ответ. Нельзя точно вычислить трансцендентную функцию алгебраически, но существуют приближения, которые достаточно хороши для инженеров. Логарифмическая линейка и таблицы тоже не точны.
«Надеюсь, им никогда не приходилось вычислять косинус для значения ≥ π/2». Нет необходимости использовать соотношение cos(π - α) = -cos(α). Используя это и подобные соотношения, необходимо вычислить только диапазон 0 ≤ α ≤ π/4. Эти преобразования могут быть использованы для sin, cos, tan и cot. В коде Apollo 11 могут быть другие функции, использующие эти преобразования, когда возможны большие аргументы.
Потрясающий анализ! Мне никогда не удавалось самостоятельно прочитать ассемблер AGC. Добро пожаловать на борт.
Хороший! Это заставляет меня хотеть написать свой собственный эмулятор AGC и попробовать его :-)
Могли ли некоторые из инструкций в начале урезаться в 2 раза до диапазона +/- 1, а затем инвертироваться, если это переносится? Если это так, поведение cos() было бы чистым для любого угла.
@MagicOctopusUrn Брограммеры среди нас, которые утверждают, что «девушки не умеют программировать», должны принять к сведению, что этот код был разработан женщиной .
Тейлор основан на производных в одной точке, это не лучшая (минимальная максимальная ошибка) подгонка по диапазону. Таким образом, ожидается, что будет использоваться аналогичный, но другой полином.
@philipp Я на самом деле написал о ней небольшую статью - образ ее, стоящей рядом со стопкой программ сборки выше, чем она сама, всегда вдохновлял меня. Программирование требует определенной проводки мозга, а не конкретного типа человека, имхо :).
У меня зашкаливают показания арифмометра!
@supinf действительно кажется, что коэффициенты оптимизированы, чтобы давать хорошие результаты выше ± π / 2. Быстрая проверка дает почти те же числа, что и в программе, а не номинальные значения правильного разложения Тейлора при x=0. pastebin.com/UnVudQs4 Кстати, очень проницательный ответ, еще раз спасибо!
@Philip: Этот код был разработан командой, состоящей в основном из мужчин и нескольких женщин во главе с Магарет Гамильтон. Она не сказала здесь , была ли она единственной женщиной в команде.
@uhoh Так что то, что они сделали, было намного лучше, чем приближение Тейлора (@zch уже предлагал это). Я отредактировал, а также связал ваш код Python. Отличный анализ - он показывает, что среднеквадратическая ошибка была для них важнее, чем максимальная ошибка.
@supinf скрипт pastebin (рифмуется с мусорной корзиной) был всего лишь быстрым тестом. Минимизация может быть на удивление сложной, и у меня не было времени тщательно ее изучить, поэтому я несколько отодвинул ваше обсуждение результатов. Спасибо!
Я надеюсь помочь, как это однажды. Пока все в моей голове. Очень унизительно.
Выбор С как константа является умеренным намеком на то, что рассматриваемый полином не является разложением Тейлора, а скорее квадратурным разложением по полиномам Чебышева или чем-то подобным.
@EP: Я не думал об этом, но мне было любопытно, как у функции оказался такой широкий полезный диапазон, поскольку мой собственный опыт работы с рядом Тейлора показал, что полезный диапазон намного меньше. Однако принятие потери точности в точках, близких к нулю, позволяет точкам, расположенным дальше, быть намного более точными.
@uhoh Поскольку проблемы минимизации выпуклые, а также появляется сообщение «Оптимизация успешно завершена». для resmrs и resmax я был достаточно уверен в результатах. Также maxiter и maxfev куда не дошли. Но по крайней мере ясно, что коэффициенты Аполлона намного лучше, чем коэффициенты Тейлора.
Алгоритмы @supinf не идеальны, и мы можем на 100% верить в их совершенство, пока нас не укусят один раз Модуль оптимизации предлагает на выбор большое количество самых разных алгоритмов, я думаю, что следующим шагом будет попробовать несколько и посмотреть насколько близки их результаты друг к другу, или, в этом случае, проверить это аналитически, чтобы увидеть, является ли это хотя бы локальным максимумом. Конечный размер Икс массив может сделать его невыпуклым причудливым образом, свернутая функция может быть негладкой (прерывистый градиент).
@supinf space.stackexchange.com/questions/31102/… — еще один связанный вопрос, если вы тоже хотите это объяснить :).
@Uwe На этой странице указаны авторы отдельных подпрограмм AGC - хотя я склоняюсь к мужчинам, я вижу в списке 5 вероятных женских имен. ibiblio.org/аполлон
@supinf У меня есть еще один вопрос о коде AGC, если вам интересно. space.stackexchange.com/q/31196/195
@NathanTuggy, в чем мир нуждается сейчас больше, чем когда-либо, так это в «лучших скобках» ;-)
Интересно, как этот код выглядит в NASM... добавлен в список проектов.
@Philipp Я не понимаю, как комментарий Magic Octopus Urn, на который вы отвечаете, предположительно подразумевает, что «девушки не умеют программировать», или любой другой комментарий из тех, которые я еще не читал на этом сайте. То, что вы не видели ассемблерный код со времен колледжа, также не обязательно означает, что вы «программист», что бы это ни значило. И последнее, но не менее важное: совершенно неразумно предполагать, что эта кодовая база была полностью написана одним человеком, независимо от того, был ли это мужчина или женщина, и посредством этого предположения игнорировать время и усилия всей команды программистов. .
@Philipp По этим причинам кажется, что основная цель вашего комментария — сделать какое-то риторическое заявление не по теме, связанное с политикой идентичности, а не поделиться какой-либо полезной и конструктивной информацией, и я считаю это совершенно неуместным в этом контексте. и установка.

Вы также просили логарифм, так что давайте сделаем и это. В отличие от функций синуса и косинуса, эта не реализуется только с помощью подхода, подобного ряду Тейлора. Алгоритм основан на сдвиге входных данных и подсчете количества сдвигов, необходимых для достижения требуемого масштаба. Я не знаю названия этого алгоритма, этот ответ на SO описывает основной принцип.

Реализация LOGявляется частью модуля CGM_GEOMETRY и помечена как

ПОДПРОГРАММА ДЛЯ ВЫЧИСЛЕНИЯ НАТУРАЛЬНОГО ЛОГА

Подпрограмма использует NORMассемблерную инструкцию, которая, согласно документации , сдвигает число в аккумуляторе (регистре "MPAC") влево до тех пор, пока не будет получено значение 0,5 и "почти 1 " [1] , и записывает количество выполненных операций сдвига в ячейку памяти, указанную в качестве второго аргумента (математический смысл операции сдвига влево - двоичное возведение в степень 2 н , показатели степени в аргументе логарифма могут быть выражены как множители, а произведения в аргументе могут быть выражены в виде сложений, поэтому упрощение л н ( 2 с с с а л е д ) в с с о н с т + л н ( с с а л е д ) работает, где с это количество смен и с о н с т предварительно вычисленное значение л н ( 2 ) ).

Затем он использует полином третьей степени для аппроксимации л н в этом интервале с жестко заданными коэффициентами [3] :

введите описание изображения здесь

В конце концов полученный ранее счетчик сдвигов снова умножается (умножается на константу 0,0216608494 [2] , используя SHORTMP).

Давление оптимизации, должно быть, было настолько велико, что они не исправили перевернутый знак перед возвратом из подпрограммы, вместо этого требуя, чтобы все сайты вызова учитывали это.

Применение подпрограммы логарифмирования:
например, как часть предсказания дальности при повторном входе в атмосферу.

---

[1] формат хранения для числа двойной точности был построен из двух 16-битных слов, где MSB каждого является знаком и формирует представление диапазона с дополнением до единицы 1 < Икс < 1 но LSB - это бит четности. Таким образом, мы имеем дело с 30-битным форматом, содержащим два знаковых бита, что вызывает некоторую головную боль при реализации эмулятора.

[2] язык ассемблера ACG позволяет CLOG2/32использовать имя идентификатора. Это вызвало дополнительную головную боль для реализации эмулятора .

[3] как были найдены коэффициенты? Комментарии к коду ассемблерного листа интерпретирующего тригнонометрического модуля (да, астронавты могли заставить ACG интерпретировать динамические инструкции) позволяют предположить, что метод был основан на работах Ч. Гастингса, особенно Approximations for Digital Computers. Издательство Принстонского университета, 1955 г. Самый сложный многочлен такого рода в ACG — это полином седьмого порядка того же модуля для вычисления а р с с о с ( Икс ) 1 Икс п ( Икс ) ).

Я подозреваю, что используется уравнение ln(arg) = ln((2^a)*b) = a*ln(2) + ln(b). a — количество сдвигов, необходимое для получения 0,5 < b < 1, так что arg = (2^a)*b. Но должна быть константа ln(2) = 0,693147, которую я не смог найти. Но ln(2)/32 = 0,02166 близко к константе 0,0215738898. 32 * .0215738898 равно 0,69036.
на второй взгляд, здесь задействован полином. строка 274 оценивает многочлен третьей степени (строка 276, 2+1) с коэффициентами .031335467 и т. д., которые следуют. Я буду подражать этому и добавлю сюжет, если у меня будет время позже.
@Uwe Константа для п ( 2 ) / 32 присутствует в строке 302.
0,0216608494 * 32 действительно равно 0,693147181. Я все еще борюсь с этим странным хранилищем дополнений с переполнением и четностью с двойной точностью, пока не приближаюсь к попытке эмуляции в C.
@uhoh Мне кажется, что 0,031335467 ( 1 Икс ) + 0,0130145859 ( 1 Икс ) 2 + 0,0215738898 ( 1 Икс ) 3 является хорошим приближением п ( Икс ) / 32 за Икс между 0,5 и 1 .
@Litho: хорошая находка в строке 302. Я должен был искать больше внизу. Удивительно, что все 9 цифр константы совпадают с рассчитанными на моем старом hp32S. 30-битная константа может содержать до 9 десятичных цифр, поэтому в двоичном представлении теряется только последняя десятичная цифра 4.
@Лито да, здорово!
@dlatikay У меня есть еще один вопрос о коде AGC, если вам интересно. space.stackexchange.com/q/31196/195

Одно дополнение к ответу @supinf :

а) Начальный DOUBLEвSPT

б) переполнения для входа x (регистр A) выше +0,5 (+90°) и потери значимости для x ниже -0,5 (-90°). В этом случае Aэто >+1 или <-1, а следующее TSсохраняет исправленное значение (фактически добавьте единицу, если оно ниже -1, или вычтите единицу, если оно больше +1) TEMKи задает Aзначение +1 ( переполнение) или -1 (недополнение). TCFКроме того , переход POLLEYигнорируется.

c) XCHзаменяется TEMKна A, поэтому теперь Aсодержит исправленное значение и TEMK±1.

г) INDEXдобавляет значение из TEMK(±1) к значению следующей ADинструкции, что молча исправляет переполнения. Поскольку LIMITSравно -0,5, это приводит к прибавлению 0,5 в случае переполнения (-0,5 + +1 = 0,5) и к вычитанию 0,5 в случае недополнения (-0,5 + -1 = -1,5 = -0,5). .

e) инвертирует COMзначение A- включая инвертирование бита переполнения - и

f) финал ADдобавляет единицу в случае переполнения и вычитает единицу в случае потери значимости. ADне выполняет коррекцию переполнения перед добавлением и устанавливает флаг переполнения после. Таким образом, каждое переполненное значение (>+135° и <-135°) вернется в диапазон [-1,+1].

Визуализация расчетов af

Если это ADпереполняется / переполняется (я не вижу, как это могло бы произойти), оно устанавливается Aв ± 1, переходит к ARG90и устанавливается Aв -( LIMITS+ A), что составляет -(-0,5+1)=-(+0,5)=-0,5 в в случае переполнения и -(-0,5-1)=-(-1,5)=-(-0,5)=+0,5 в случае недостаточного переполнения. Сначала я думал, что это произойдет при x > +135° или x < -135°, но, похоже, это не так.

Но такая настройка корпуса <-90° и >+90° мне кажется неправильной. Я ожидаю, что строка f будет от (+0,5,+1,0) до (+1,0,+0,0) и от (-0,5,-1,0) до (-1,0,-0,0). Это было бы так, если бы COMследовало непосредственно XCHбез шага d.

Пожалуйста, поправьте меня, если я ошибаюсь в некоторых частях, я только недавно видел этот код и пытался понять его с помощью AGC Instruction Set .