x86マシンコード、39バイト
;;; Obtain a "reversed" version of the input value.
;;;
;;; To do this, each iteration of a loop, we take the input value modulo 10,
;;; add that to our accumulator (EDI), multiply the accumulator by 10, and
;;; divide the input value by 10. x86's DIV instruction does both modulo and
;;; division as a single operation, with the cost of clobbering two output
;;; registers (EAX and EDX). We clobber the input value throughout the loop
;;; (the way we know we're done is when it becomes 0---that means that we have
;;; pulled all of the digits off of it), so we need to save a copy of it first.
89 C8 mov eax, ecx ; make copy of input
31 FF xor edi, edi ; clear accumulator
6A 0A push 10
5E pop esi ; set ESI to 10
Reverse:
0F AF FE imul edi, esi ; accumulator *= 10
99 cdq ; zero EDX in preparation for division
F7 F6 div esi ; EDX:EAX / 10 (EAX is quot, EDX is rem)
01 D7 add edi, edx ; accumulator += remainder
85 C0 test eax, eax ; was quotient 0?
75 F4 jnz Reverse ; if not, keep looping and extracting digits
;;; At this point, EAX is 0 (clobbered throughout the loop),
;;; ECX still contains a copy of our original input, and
;;; EDI contains the 'reversed' input.
89 C8 mov eax, ecx ; make another copy of the input
F7 E7 mul edi ; multiply input (implicit EAX operand)
; by 'reversed', with result in EDX:EAX
; (note: EDX will be 0)
;;; Compute the greatest common denominator (GCD) of the input and
;;; the 'reversed' values, using a subtraction-based algorithm.
GCD_0:
39 CF cmp edi, ecx ; compare the two values
72 02 jb GCD_1 ; go to GCD_1 if less than
87 F9 xchg ecx, edi ; swap values
GCD_1:
29 F9 sub ecx, edi ; subtract
75 F6 jnz GCD_0 ; if sum != 0, go back to the top
;;; Square the GCD.
0F AF FF imul edi, edi
;;; Divide the product of input and 'reversed' by the square of the GCD.
;;; Remember from above that the product of input and 'reversed' is in
;;; the EAX register, and we can assume EDX is 0, so we don't need to do
;;; a CDQ here in preparation for the division. Using EAX as the implicit
;;; source operand saves us a byte when encoding DIV.
F7 F7 div edi
;;; The DIV instruction placed the quotient in EAX,
;;; which is what we want to return to the caller.
C3 ret
上記の関数は、指定された入力パラメーターの「非共通因子数」を計算します。レジスタベースの__fastcall呼び出し規約に従って、パラメータがECXレジスタに渡されます。EAXすべてのx86呼び出し規約と同様に、結果はレジスタに返されます。
オンラインでお試しください!
これは、このようなコンパクトなフォームで書くのに非常に長い時間がかかりましたが、楽しい練習でした。x86 DIV命令の暗黙のオペランドの制約内で、可能な限り最適なレジスタスケジューリングを実現するための多くのゆがみと、可能な限り短いエンコーディングMULとXCHG命令の使用を試みます。誰かがそれをさらに短縮する別の方法を考えられるかどうかを知りたいと思います。私の脳は最後までかなり揚げていました。次回、コンパイラをご覧ください!(これはあるものの道あなたがのようなものを削除し、サイズの制約なしに、わずかにそれを微調整場合は特に...コンパイラが生成されるものよりもより良いコードXCHG。)