Mã máy x87, 11 byte
D9 EB
DA 31
D9 F2
DD D8
DA 09
C3
Các byte mã trên xác định hàm tính diện tích của một n-gon thông thường với một apothem là 1. Nó sử dụng các lệnh x87 FPU (đơn vị dấu phẩy động cổ điển trên bộ xử lý x86) để thực hiện tính toán này.
Theo một quy ước gọi dựa trên thanh ghi x86 tiêu chuẩn (trong trường hợp này __fastcall
), đối số của hàm là một con trỏ tới số nguyên, được truyền trong thanh ECX
ghi. Kết quả của hàm là một giá trị dấu phẩy động, được trả về ở đầu ngăn xếp dấu phẩy động x87 (thanh ghi ST0
).
Hãy thử trực tuyến!
Ma thuật lắp ráp bất khả xâm phạm:
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
Như bạn có thể thấy, về cơ bản, đây chỉ là một tính toán đơn giản của công thức đã cho,
result = n * tan (π / n)
Chỉ có một vài điều thú vị được chỉ ra:
- FPU x87 có một hướng dẫn chuyên dụng để tải giá trị không đổi PI (
FLDPI
). Điều này hiếm khi được sử dụng, thậm chí trở lại vào ban ngày (và rõ ràng là ít hơn bây giờ), nhưng nó có kích thước ngắn hơn so với việc nhúng một hằng số vào nhị phân của bạn và tải nó.
- Lệnh x87 FPU để tính tiếp tuyến,
FPTAN
thay thế giá trị của thanh ghi đầu vào (đỉnh của ngăn xếp FPU) bằng kết quả, nhưng cũng đẩy một hằng số 1.0 lên trên đỉnh của ngăn xếp FPU. Điều này được thực hiện để tương thích ngược với 8087 (Tôi không biết tại sao điều này được thực hiện trên 8087; có lẽ là một lỗi). Điều đó có nghĩa là chúng ta cần loại bỏ giá trị không cần thiết này khỏi ngăn xếp. Cách nhanh nhất và ngắn nhất để làm điều đó là đơn giản FSTP st0
, như chúng ta sử dụng ở đây. Chúng tôi cũng có thể thực hiện phép nhân và pop , vì nhân với 1.0 sẽ không thay đổi kết quả, nhưng đây cũng là 2 byte (vì vậy không thắng trong kích thước mã), có thể sẽ thực thi chậm hơn và có thể đưa ra sự không xác định không cần thiết vào kết quả.
Mặc dù một lập trình viên hoặc trình biên dịch hiện đại sẽ sử dụng tập lệnh SSE (và phiên bản mới hơn), thay vì x87 cũ, điều này sẽ đòi hỏi nhiều mã hơn để thực hiện, vì không có lệnh nào để tính tiếp tuyến trong các ISA mới hơn này.
Area@RegularPolygon
nên đượcArea@*RegularPolygon
; như bây giờ, nó không thể bị bắt trong một biến. Đó là,f = Area@RegularPolygon; f[3]
không hoạt động. Thảo luận meta có liên quan