Машинный код x87, 11 байт
D9 EB
DA 31
D9 F2
DD D8
DA 09
C3
Приведенные выше байты кода определяют функцию, которая вычисляет площадь обычного n-гона с апофемом 1. Для этого вычисления используются инструкции FPU x87 (классическая единица с плавающей запятой на процессорах x86).
Следуя стандартному соглашению о вызовах на основе регистров x86 (в данном случае __fastcall
), аргумент функции является указателем на целое число, переданное в ECX
регистре. Результатом функции является значение с плавающей запятой, возвращаемое вверху стека с плавающей запятой x87 (регистр ST0
).
Попробуйте онлайн!
Неуправляемая сборка мнемоники:
D9 EB fldpi ; load constant PI at top of FPU stack
DA 31 fidiv DWORD PTR [ecx] ; divide PI by integer input (loaded from pointer
; in ECX), leaving result at top of FPU stack
D9 F2 fptan ; compute tangent of value at top of FPU stack
DD D8 fstp st0 ; pop junk value (FPTAN pushes 1.0 onto stack)
DA 09 fimul DWORD PTR [ecx] ; multiply by integer input (again, loaded via ECX)
C3 ret ; return control to caller
Как вы можете видеть, это в основном простое вычисление по заданной формуле,
результат = n * tan (π / n)
Только пара интересных вещей указывает на то, что:
- FPU x87 имеет специальную инструкцию для загрузки постоянного значения PI (
FLDPI
). Это редко использовалось, даже в те времена (и, очевидно, намного меньше сейчас), но оно короче по размеру, чем встраивание константы в ваш двоичный файл и его загрузка.
- Инструкция x87 FPU для вычисления тангенса
FPTAN
заменяет значение входного регистра (вершина стека FPU) на результат, но также помещает константу 1.0 в верхнюю часть стека FPU. Это сделано для обратной совместимости с 8087 (я понятия не имею, почему это было сделано на 8087; вероятно, ошибка). Это означает, что мы должны вытолкнуть это ненужное значение из стека. Самый быстрый и короткий способ сделать это - простой FSTP st0
, как мы используем здесь. Мы могли бы также сделать умножение-и-всплытие , поскольку умножение на 1,0 не изменит результат, но это также 2 байта (поэтому нет выигрыша в размере кода), вероятно, будет выполняться медленнее и может привести к ненужной неопределенности в результат.
Хотя современный программист или компилятор будет использовать набор инструкций SSE (и более поздних), а не устаревший x87, для этого потребуется больше кода для реализации, поскольку нет единой инструкции для вычисления касательной в этих более новых ISA.
Area@RegularPolygon
должно бытьArea@*RegularPolygon
; как сейчас, он не может быть записан в переменной. То естьf = Area@RegularPolygon; f[3]
не работает. Соответствующая мета-дискуссия