isqrt: add integer square root builtin to all three impls
Semantics: (isqrt n) → floor(sqrt(n)). Negative argument errors.
Matches Python 3.8+ math.isqrt and R7RS exact-integer-sqrt contract.
- Python: wraps math.isqrt via lambda registration
- C: hand-rolled bit-by-bit algorithm in bi_isqrt (O(log n), no FPU)
- asm: new BI_ISQRT=109, bit-by-bit algorithm in integer registers
(%r8/%r9/%r10). Negative input → stderr + exit(1) like other
errors. GC builtin constants bumped to 110-114.
Tests:
- tests/functional.lsp: 7 shared tests (0, 1, perfect squares, floor
cases, large values). Python + C now 196 each (was 189).
- asm/test.sh: 5 asm-local tests. asm suite now 142 (was 137).
MOAD: all three implementations O(log n), no O(N²) hazards.
This commit is contained in:
parent
f57de49f7b
commit
6e9d3ea52f
9 changed files with 98 additions and 8 deletions
BIN
asm/lumbda
BIN
asm/lumbda
Binary file not shown.
BIN
asm/lumbda-gc
BIN
asm/lumbda-gc
Binary file not shown.
BIN
asm/lumbda-gc.o
BIN
asm/lumbda-gc.o
Binary file not shown.
BIN
asm/lumbda.o
BIN
asm/lumbda.o
Binary file not shown.
73
asm/lumbda.s
73
asm/lumbda.s
|
|
@ -194,15 +194,16 @@
|
|||
.equ BI_HS_SIZE, 106
|
||||
.equ BI_HS_LIST, 107
|
||||
.equ BI_TCPSENDFILE, 108
|
||||
.equ BI_ISQRT, 109
|
||||
.ifdef GC_NAIVE
|
||||
.equ BI_GC_COLLECT, 109
|
||||
.equ BI_GC_STATS, 110
|
||||
.equ BI_WITH_ARENA, 111
|
||||
.equ BI_ARENA_STATS, 112
|
||||
.equ BI_ARENA_SET_MODE, 113
|
||||
.equ BI_COUNT, 114
|
||||
.equ BI_GC_COLLECT, 110
|
||||
.equ BI_GC_STATS, 111
|
||||
.equ BI_WITH_ARENA, 112
|
||||
.equ BI_ARENA_STATS, 113
|
||||
.equ BI_ARENA_SET_MODE, 114
|
||||
.equ BI_COUNT, 115
|
||||
.else
|
||||
.equ BI_COUNT, 109
|
||||
.equ BI_COUNT, 110
|
||||
.endif
|
||||
|
||||
# ============================================================
|
||||
|
|
@ -299,6 +300,7 @@ bn_listp: .byte 5; .ascii "list?"
|
|||
bn_substr: .byte 9; .ascii "substring"
|
||||
bn_expt: .byte 4; .ascii "expt"
|
||||
bn_gcd: .byte 3; .ascii "gcd"
|
||||
bn_isqrt: .byte 5; .ascii "isqrt"
|
||||
bn_integerp: .byte 8; .ascii "integer?"
|
||||
bn_portalsave: .byte 11; .ascii "portal-save"
|
||||
bn_portalresume:.byte 13; .ascii "portal-resume"
|
||||
|
|
@ -388,6 +390,7 @@ bi_names:
|
|||
.quad bn_htexists, bn_htsize, bn_htkeys, bn_htvals, bn_htalist
|
||||
.quad bn_hsmake, bn_hsp, bn_hsadd, bn_hshas, bn_hssize, bn_hslist
|
||||
.quad bn_tcpsendfile
|
||||
.quad bn_isqrt
|
||||
.ifdef GC_NAIVE
|
||||
.quad bn_gccollect, bn_gcstats, bn_witharena, bn_arenastats, bn_arenamode
|
||||
.endif
|
||||
|
|
@ -399,6 +402,8 @@ err_notproc: .ascii "Error: not a procedure\n"
|
|||
.equ err_notproc_len, . - err_notproc
|
||||
err_oom: .ascii "Error: out of memory\n"
|
||||
.equ err_oom_len, . - err_oom
|
||||
err_isqrt_neg: .ascii "Error: isqrt: negative argument\n"
|
||||
.equ err_isqrt_neg_len, . - err_isqrt_neg
|
||||
|
||||
# Print strings
|
||||
s_true: .ascii "#t"
|
||||
|
|
@ -3355,6 +3360,8 @@ eval_list:
|
|||
je bi_expt
|
||||
cmpq $BI_GCD, %rax
|
||||
je bi_gcd
|
||||
cmpq $BI_ISQRT, %rax
|
||||
je bi_isqrt
|
||||
cmpq $BI_INTEGERP, %rax
|
||||
je bi_integerp
|
||||
cmpq $BI_PORTALSAVE, %rax
|
||||
|
|
@ -4663,6 +4670,58 @@ bi_gcd:
|
|||
call make_int
|
||||
RET_VAL
|
||||
|
||||
# bi_isqrt: floor of integer square root (bit-by-bit, no FPU).
|
||||
# Negative input -> error exit. Registers: %r8 = x, %r9 = res, %r10 = bit.
|
||||
bi_isqrt:
|
||||
GETARG %rax
|
||||
sarq $3, %rax # untag
|
||||
testq %rax, %rax
|
||||
js .bisqrt_neg
|
||||
cmpq $2, %rax
|
||||
jl .bisqrt_small # v < 2 -> result is v itself
|
||||
movq %rax, %r8 # x
|
||||
xorq %r9, %r9 # res
|
||||
movq $1, %r10
|
||||
shlq $62, %r10 # bit = 1<<62
|
||||
.bisqrt_align:
|
||||
cmpq %r8, %r10
|
||||
jbe .bisqrt_loop
|
||||
shrq $2, %r10
|
||||
jmp .bisqrt_align
|
||||
.bisqrt_loop:
|
||||
testq %r10, %r10
|
||||
jz .bisqrt_ret
|
||||
movq %r9, %rcx
|
||||
addq %r10, %rcx # rcx = res + bit
|
||||
cmpq %rcx, %r8
|
||||
jb .bisqrt_no
|
||||
subq %rcx, %r8 # x -= res + bit
|
||||
shrq $1, %r9
|
||||
addq %r10, %r9 # res = (res>>1) + bit
|
||||
jmp .bisqrt_next
|
||||
.bisqrt_no:
|
||||
shrq $1, %r9 # res >>= 1
|
||||
.bisqrt_next:
|
||||
shrq $2, %r10 # bit >>= 2
|
||||
jmp .bisqrt_loop
|
||||
.bisqrt_ret:
|
||||
movq %r9, %rdi
|
||||
call make_int
|
||||
RET_VAL
|
||||
.bisqrt_small:
|
||||
movq %rax, %rdi
|
||||
call make_int
|
||||
RET_VAL
|
||||
.bisqrt_neg:
|
||||
movq $SYS_WRITE, %rax
|
||||
movq $2, %rdi
|
||||
leaq err_isqrt_neg(%rip), %rsi
|
||||
movq $err_isqrt_neg_len, %rdx
|
||||
syscall
|
||||
movq $SYS_EXIT, %rax
|
||||
movq $1, %rdi
|
||||
syscall
|
||||
|
||||
bi_vector:
|
||||
# (vector e1 e2 ...) — build from remaining args in %r12
|
||||
# Count args
|
||||
|
|
|
|||
|
|
@ -52,6 +52,11 @@ check "max" "(max 3 1 4)" "4"
|
|||
check "expt" "(* 2 2 2 2 2 2 2 2 2 2)" "1024"
|
||||
check "div" "(/ 10 2)" "5"
|
||||
check "expt-bi" "(expt 2 10)" "1024"
|
||||
check "isqrt-0" "(isqrt 0)" "0"
|
||||
check "isqrt-1" "(isqrt 1)" "1"
|
||||
check "isqrt-perfect" "(isqrt 144)" "12"
|
||||
check "isqrt-floor" "(isqrt 10)" "3"
|
||||
check "isqrt-big" "(isqrt 1000000000000)" "1000000"
|
||||
check "odd?" "(odd? 3)" "#t"
|
||||
check "odd?-even" "(odd? 4)" "#f"
|
||||
check "even?" "(even? 4)" "#t"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue