숫자가 제곱인지 테스트


16

레지스터 에 64 비트 부호없는 정수를 제공 한 GOLF 어셈블리 프로그램을 작성하면 정사각형 이면 n0이 아닌 값을 레지스터에 , 그렇지 않으면 에 값을 넣 습니다 .sn0s

당신의 골프 (조립 후) 진은 4096 바이트에 맞게해야합니다.


프로그램은 다음 Python3 프로그램 ( GOLF 디렉토리에 넣어야 함)을 사용하여 채점됩니다 .

import random, sys, assemble, golf, decimal

def is_square(n):
    nd = decimal.Decimal(n)
    with decimal.localcontext() as ctx:
        ctx.prec = n.bit_length() + 1
        i = int(nd.sqrt())
        return i*i == n

with open(sys.argv[1]) as in_file:
    binary, debug = assemble.assemble(in_file)

score = 0
random.seed(0)
for i in range(1000):
    cpu = golf.GolfCPU(binary)

    if random.randrange(16) == 0: n = random.randrange(2**32)**2
    else:                         n = random.randrange(2**64)

    cpu.regs["n"] = n
    cpu.run()
    if bool(cpu.regs["s"]) != is_square(n):
        raise RuntimeError("Incorrect result for: {}".format(n))
    score += cpu.cycle_count
    print("Score so far ({}/1000): {}".format(i+1, score))

print("Score: ", score)

GOLF 를 최신 버전으로 업데이트하십시오 git pull. 를 사용하여 점수 프로그램을 실행하십시오 python3 score.py your_source.golf.

정적 시드를 사용하여 약 1/16이 정사각형 인 숫자 집합을 생성합니다. 이 숫자 집합을 향한 최적화는 문제의 정신에 위배되며 언제든지 종자를 바꿀 수 있습니다. 프로그램은 음수가 아닌 64 비트 입력 번호에 대해서만 작동해야합니다.

최저 점수가 이깁니다.


GOLF 는 매우 새롭기 때문에 여기에 몇 가지 포인터를 포함하겠습니다. 모든 지침과 사이클 비용 이 포함 된 GOLF 사양을 읽어야 합니다 . Github 리포지토리에서 예제 프로그램을 찾을 수 있습니다.

수동 테스트의 경우을 실행하여 프로그램을 바이너리로 컴파일하십시오 python3 assemble.py your_source.golf. 그런 다음을 사용하여 프로그램을 실행 하면 42 python3 golf.py -p s your_source.bin n=42n설정된 상태 에서 프로그램이 시작되고 s종료 후 레지스터 및 사이클 카운트가 인쇄 됩니다. 프로그램 종료시 레지스터 내용의 모든 값을 -d플래그 와 함께 --help보십시오. 모든 플래그를 보려면 사용 하십시오.


테스트 당 ~ 64 작업을 저장하기 위해 32 반복 루프를 풀었습니다. 그것은 아마도 도전의 정신을 벗어난 것입니다. 속도를 코드 크기로 나눌 때 더 잘 작동 할 수 있습니까?
Sparr

바이너리가 4096 바이트 인 경우 @Sparr 루프 언 롤링이 허용됩니다. 이 한계가 너무 높다고 생각하십니까? 나는 그것을 낮추고 자합니다.
orlp

@Sparr 현재 바이너리는 1.3k이지만 32 반복 루프 언 롤링이 약간 많다고 생각합니다. 1024 바이트의 이진 제한은 어떻게 들립니까?
orlp

모든 참가자에게 경고! 로 GOLF 인터프리터를 업데이트하십시오 git pull. 왼쪽 쉬프트 피연산자에서 제대로 줄 바꿈되지 않은 버그를 발견했습니다.
orlp

잘 모르겠습니다. 1024는 한 번만 반복하면됩니다. 언 롤링으로 테스트 당 ~ 62 ops를 저장했습니다. 나는 누군가가 룩업 테이블로 잘 사용하기 위해 많은 공간을 두었을 것이라고 생각합니다. 32 비트 제곱근에 대해 2-8k 개의 조회 테이블을 원하는 알고리즘을 보았습니다.
Sparr

답변:


2

점수 : 22120 (3414 바이트)

내 솔루션은 3kB 조회 테이블을 사용하여 결과 크기에 따라 0 ~ 3 회 반복되는 뉴턴의 메소드 솔버를 시드합니다.

    lookup_table = bytes(int((16*n)**0.5) for n in range(2**10, 2**12))

    # use orlp's mod-64 trick
    and b, n, 0b111111
    shl v, 0xc840c04048404040, b
    le q, v, 0
    jz not_square, q
    jz is_square, n

    # x will be a shifted copy of n used to index the lookup table.
    # We want it shifted (by a multiple of two) so that the two most 
    # significant bits are not both zero and no overflow occurs.
    # The size of n in bit *pairs* (minus 8) is stored in b.
    mov b, 24
    mov x, n 
    and c, x, 0xFFFFFFFF00000000
    jnz skip32, c
    shl x, x, 32
    sub b, b, 16
skip32:
    and c, x, 0xFFFF000000000000
    jnz skip16, c
    shl x, x, 16
    sub b, b, 8
skip16:
    and c, x, 0xFF00000000000000
    jnz skip8, c
    shl x, x, 8
    sub b, b, 4
skip8:
    and c, x, 0xF000000000000000
    jnz skip4, c
    shl x, x, 4
    sub b, b, 2
skip4:
    and c, x, 0xC000000000000000
    jnz skip2, c
    shl x, x, 2
    sub b, b, 1
skip2:

    # now we shift x so it's only 12 bits long (the size of our lookup table)
    shr x, x, 52

    # and we store the lookup table value in x
    add x, x, data(lookup_table)
    sub x, x, 2**10
    lbu x, x

    # now we shift x back to the proper size
    shl x, x, b

    # x is now an intial estimate for Newton's method.
    # Since our lookup table is 12 bits, x has at least 6 bits of accuracy
    # So if b <= -2, we're done; else do an iteration of newton
    leq c, b, -2
    jnz end_newton, c
    divu q, r, n, x
    add x, x, q
    shr x, x, 1

    # We now have 12 bits of accuracy; compare b <= 4
    leq c, b, 4
    jnz end_newton, c
    divu q, r, n, x
    add x, x, q
    shr x, x, 1

    # 24 bits, b <= 16
    leq c, b, 16
    jnz end_newton, c
    divu q, r, n, x
    add x, x, q
    shr x, x, 1

    # 48 bits, we're done!

end_newton:

    # x is the (integer) square root of n: test x*x == n
    mulu x, h, x, x
    cmp s, n, x
    halt 0

is_square:
    mov s, 1

not_square:
    halt 0

10

점수 : 27462

내가 골프 챌린지 에서 경쟁 할 시간에 대해 : D

    # First we look at the last 6 bits of the number. These bits must be
    # one of the following:
    #
    #     0x00, 0x01, 0x04, 0x09, 0x10, 0x11,
    #     0x19, 0x21, 0x24, 0x29, 0x31, 0x39
    #
    # That's 12/64, or a ~80% reduction in composites!
    #
    # Conveniently, a 64 bit number can hold 2**6 binary values. So we can
    # use a single integer as a lookup table, by shifting. After shifting
    # we check if the top bit is set by doing a signed comparison to 0.

    and b, n, 0b111111
    shl v, 0xc840c04048404040, b
    le q, v, 0
    jz no, q
    jz yes, n

    # Hacker's Delight algorithm - Newton-Raphson.
    mov c, 1
    sub x, n, 1
    geu q, x, 2**32-1
    jz skip32, q
    add c, c, 16
    shr x, x, 32
skip32:
    geu q, x, 2**16-1
    jz skip16, q
    add c, c, 8
    shr x, x, 16
skip16:
    geu q, x, 2**8-1
    jz skip8, q
    add c, c, 4
    shr x, x, 8
skip8:
    geu q, x, 2**4-1
    jz skip4, q
    add c, c, 2
    shr x, x, 4
skip4:
    geu q, x, 2**2-1
    add c, c, q

    shl g, 1, c
    shr t, n, c
    add t, t, g
    shr h, t, 1

    leu q, h, g
    jz newton_loop_done, q
newton_loop:
    mov g, h
    divu t, r, n, g
    add t, t, g
    shr h, t, 1
    leu q, h, g
    jnz newton_loop, q
newton_loop_done:

    mulu u, h, g, g
    cmp s, u, n 
    halt 0
yes:
    mov s, 1
no:
    halt 0

조회 아이디어를 훔치면 점수가 161558에서 47289로 떨어집니다. 알고리즘이 여전히 승리합니다.
Sparr

뉴턴 루프 풀기를 시도 했습니까? 최악의 경우 몇 번의 반복이 필요합니까?
Sparr

@Sparr 예, 반복 횟수의 편차가 높기 때문에 풀기 속도가 빠르지 않습니다.
orlp

0 회 또는 1 회 반복으로 완료됩니까? 최대는 얼마입니까?
Sparr

조회 테이블 아이디어는 stackoverflow.com/a/18686659/4339987에도 있습니다.
lirtosiast

5

점수 : 161558 227038 259038 260038 263068

내가 찾을 수있는 가장 빠른 정수 제곱근 알고리즘을 취하고 나머지가 0인지 여부를 반환합니다.

# based on http://www.cc.utah.edu/~nahaj/factoring/isqrt.c.html
# converted to GOLF assembly for http://codegolf.stackexchange.com/questions/49356/testing-if-a-number-is-a-square

# unrolled for speed, original source commented out at bottom
start:
    or u, t, 1 << 62
    shr t, t, 1
    gequ v, n, u
    jz nope62, v
    sub n, n, u
    or t, t, 1 << 62
    nope62:

    or u, t, 1 << 60
    shr t, t, 1
    gequ v, n, u
    jz nope60, v
    sub n, n, u
    or t, t, 1 << 60
    nope60:

    or u, t, 1 << 58
    shr t, t, 1
    gequ v, n, u
    jz nope58, v
    sub n, n, u
    or t, t, 1 << 58
    nope58:

    or u, t, 1 << 56
    shr t, t, 1
    gequ v, n, u
    jz nope56, v
    sub n, n, u
    or t, t, 1 << 56
    nope56:

    or u, t, 1 << 54
    shr t, t, 1
    gequ v, n, u
    jz nope54, v
    sub n, n, u
    or t, t, 1 << 54
    nope54:

    or u, t, 1 << 52
    shr t, t, 1
    gequ v, n, u
    jz nope52, v
    sub n, n, u
    or t, t, 1 << 52
    nope52:

    or u, t, 1 << 50
    shr t, t, 1
    gequ v, n, u
    jz nope50, v
    sub n, n, u
    or t, t, 1 << 50
    nope50:

    or u, t, 1 << 48
    shr t, t, 1
    gequ v, n, u
    jz nope48, v
    sub n, n, u
    or t, t, 1 << 48
    nope48:

    or u, t, 1 << 46
    shr t, t, 1
    gequ v, n, u
    jz nope46, v
    sub n, n, u
    or t, t, 1 << 46
    nope46:

    or u, t, 1 << 44
    shr t, t, 1
    gequ v, n, u
    jz nope44, v
    sub n, n, u
    or t, t, 1 << 44
    nope44:

    or u, t, 1 << 42
    shr t, t, 1
    gequ v, n, u
    jz nope42, v
    sub n, n, u
    or t, t, 1 << 42
    nope42:

    or u, t, 1 << 40
    shr t, t, 1
    gequ v, n, u
    jz nope40, v
    sub n, n, u
    or t, t, 1 << 40
    nope40:

    or u, t, 1 << 38
    shr t, t, 1
    gequ v, n, u
    jz nope38, v
    sub n, n, u
    or t, t, 1 << 38
    nope38:

    or u, t, 1 << 36
    shr t, t, 1
    gequ v, n, u
    jz nope36, v
    sub n, n, u
    or t, t, 1 << 36
    nope36:

    or u, t, 1 << 34
    shr t, t, 1
    gequ v, n, u
    jz nope34, v
    sub n, n, u
    or t, t, 1 << 34
    nope34:

    or u, t, 1 << 32
    shr t, t, 1
    gequ v, n, u
    jz nope32, v
    sub n, n, u
    or t, t, 1 << 32
    nope32:

    or u, t, 1 << 30
    shr t, t, 1
    gequ v, n, u
    jz nope30, v
    sub n, n, u
    or t, t, 1 << 30
    nope30:

    or u, t, 1 << 28
    shr t, t, 1
    gequ v, n, u
    jz nope28, v
    sub n, n, u
    or t, t, 1 << 28
    nope28:

    or u, t, 1 << 26
    shr t, t, 1
    gequ v, n, u
    jz nope26, v
    sub n, n, u
    or t, t, 1 << 26
    nope26:

    or u, t, 1 << 24
    shr t, t, 1
    gequ v, n, u
    jz nope24, v
    sub n, n, u
    or t, t, 1 << 24
    nope24:

    or u, t, 1 << 22
    shr t, t, 1
    gequ v, n, u
    jz nope22, v
    sub n, n, u
    or t, t, 1 << 22
    nope22:

    or u, t, 1 << 20
    shr t, t, 1
    gequ v, n, u
    jz nope20, v
    sub n, n, u
    or t, t, 1 << 20
    nope20:

    or u, t, 1 << 18
    shr t, t, 1
    gequ v, n, u
    jz nope18, v
    sub n, n, u
    or t, t, 1 << 18
    nope18:

    or u, t, 1 << 16
    shr t, t, 1
    gequ v, n, u
    jz nope16, v
    sub n, n, u
    or t, t, 1 << 16
    nope16:

    or u, t, 1 << 14
    shr t, t, 1
    gequ v, n, u
    jz nope14, v
    sub n, n, u
    or t, t, 1 << 14
    nope14:

    or u, t, 1 << 12
    shr t, t, 1
    gequ v, n, u
    jz nope12, v
    sub n, n, u
    or t, t, 1 << 12
    nope12:

    or u, t, 1 << 10
    shr t, t, 1
    gequ v, n, u
    jz nope10, v
    sub n, n, u
    or t, t, 1 << 10
    nope10:

    or u, t, 1 << 8
    shr t, t, 1
    gequ v, n, u
    jz nope8, v
    sub n, n, u
    or t, t, 1 << 8
    nope8:

    or u, t, 1 << 6
    shr t, t, 1
    gequ v, n, u
    jz nope6, v
    sub n, n, u
    or t, t, 1 << 6
    nope6:

    or u, t, 1 << 4
    shr t, t, 1
    gequ v, n, u
    jz nope4, v
    sub n, n, u
    or t, t, 1 << 4
    nope4:

    or u, t, 1 << 2
    shr t, t, 1
    gequ v, n, u
    jz nope2, v
    sub n, n, u
    or t, t, 1 << 2
    nope2:

    or u, t, 1 << 0
    shr t, t, 1
    gequ v, n, u
    jz nope0, v
    sub n, n, u
    nope0:

end:
    not s, n        # return !remainder
    halt 0


# before unrolling...
#
# start:
#     mov b, 1 << 62  # squaredbit = 01000000...
# loop:               # do {
#     or u, b, t      #   u = squaredbit | root
#     shr t, t, 1     #   root >>= 1
#     gequ v, n, u    #   if remainder >= u:
#     jz nope, v
#     sub n, n, u     #       remainder = remainder - u
#     or t, t, b      #       root = root | squaredbit
# nope:
#     shr b, b, 2     #   squaredbit >>= 2
#     jnz loop, b      # } while (squaredbit > 0)
# end:
#     not s, n        # return !remainder
#     halt 0

편집 1 : 제곱 테스트를 제거하고! remainder를 직접 반환하고 테스트 당 3 ops를 저장하십시오.

편집 2 : 나머지를 n으로 직접 사용하고 테스트 당 1 op를 저장하십시오.

편집 3 : 루프 조건을 단순화하고 테스트 당 32 ops 저장

편집 4 : 루프를 풀고 테스트 당 약 65 ops를 절약하십시오.


1
당신이 쓸 수 있도록, 사용 설명서에 전체 파이썬 표현식을 사용할 수 있습니다 0x4000000000000000으로 1 << 62:
orlp

3

점수 : 344493

[1, 4294967296)대략적인 간격 으로 간단한 이진 검색을 수행 한 sqrt(n)다음 n완벽한 제곱 인지 확인합니다 .

mov b, 4294967296
mov c, -1

lesser:
    add a, c, 1

start:
    leu k, a, b
    jz end, k

    add c, a, b
    shr c, c, 1

    mulu d, e, c, c

    leu e, d, n
    jnz lesser, e
    mov b, c
    jmp start

end:
    mulu d, e, b, b
    cmp s, d, n

    halt 0

좋은 시작 답변! 당신의 프로그래밍에 대한 의견이 있으십니까 골프 어셈블리를, 나는 위해 만든 도구 골프 , 또는 도전? 이러한 유형의 도전은 매우 새롭고 피드백을 듣고 싶어합니다. :)
orlp

귀하의 답변은 슬프게도 n = 0에 버그가 있습니다, 0은 0 제곱입니다 :)
orlp

@orlp fixed for n = 0. 또한 실행 중 레지스터 값을 인쇄하는 명령을 추가하여 GOLF 프로그램을 쉽게 디버깅 할 수 있습니다.
es1024

나는 그러한 명령을 추가하지 않을 것입니다 (즉, 도전 과제는 허용되지 않는 디버깅 명령에 대한 규칙을 추가해야 함을 의미합니다). 대화식 지점과 모든 레지스터 내용을보고 대화 형 디버깅을 계획했습니다.
orlp

이진 검색에 가중치를 부여하여 중간 지점 이외의 다른 곳에 착륙함으로써 속도를 높일 수 있습니다. 아마도 두 값의 기하학적 평균?
Sparr
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.