code wiki / _hdl_build / nx_mathspec_atan.nx
nx_mathspec_atan.nx source
↩ module page · 160 lines · 5153 B
1// nx_mathspec_atan.nx -- SOVEREIGN SPEC EMITTER for the ATAN kernel: every
2// constant computed on the 120-bit bigfloat (oracle organ nx_bigfloat120_atan),
3// written to _pm_atan_spec.nx for the MATH_KERNEL/ATAN emitter. No python.
4//
5// Kernel scheme (accurate-table): anchors c_j = j/8, j = 0..20. For
6// x < 41/16 the kernel takes j = nearest(8x), t = (x - c_j)/(1 + x*c_j)
7// (|t| <= 1/16, x - c_j Sterbenz-exact), atan(x) = A_hi[j] + (A_lo[j] + P(t))
8// with P an 8-coeff odd Taylor poly (truncation < 2^-64 rel). For x >= 41/16
9// it folds atan(x) = pi/2 - atan(1/x); there 1/x < 0.4 so the fold target sits
10// 2 binades below the result and the transferred error is damped 4x.
11//
12// Layout: c[0]=one c[1]=half c[2]=eight c[3]=pi2_hi c[4]=pi2_lo c[5]=cut(41/16)
13// c[6..26] anchors j/8 (j=0..20)
14// c[27..47] A_hi[j] = fl(atan(j/8))
15// c[48..68] A_lo[j] = fl(atan(j/8) - A_hi[j]) (signed)
16// c[69..76] poly coeffs hi-first: -1/15 1/13 -1/11 1/9 -1/7 1/5 -1/3 1
17// NEGATIVE literals emitted in `0 - N` form (unary-minus literal landmine).
18// license_tier: ORIGINAL
19import "nx_syscalls.nx"
20import "nx_pattern_emit.nx"
21import "nx_bigfloat120.nx"
22import "nx_bigfloat120_div.nx"
23import "nx_bigfloat120_trig.nx"
24import "nx_bigfloat120_atan.nx"
25const K_MAGIC_999999: i64 = 999999
26const K_MAGIC_5625: i64 = 5625
27
28func mat_wlit(fd: i64, v: i64) -> i64 {
29 if v < 0 {
30 pe_w(fd, "0 - " as *u8)
31 pe_wn(fd, 0 - v)
32 return 0
33 }
34 pe_wn(fd, v)
35 return 0
36}
37
38func mat_emit_row(fd: i64, idx: i64, v: i64) -> i64 {
39 pe_w(fd, " c[" as *u8); pe_wn(fd, idx); pe_w(fd, "] = " as *u8)
40 mat_wlit(fd, v)
41 pe_w(fd, "\n" as *u8)
42 return 0
43}
44
45// atan(j/8) on the bigfloat for j = 0..20 (j > 8 folds through pi/2 - atan(8/j))
46func mat_atan_j8(out: *i64, j: i64) -> i64 {
47 if j == 0 { out[0] = 0 - K_MAGIC_999999; out[1] = 0; out[2] = 0; return 0 }
48 let one: *i64 = bf_new()
49 bf_set_int(one, 1)
50 if j <= 8 {
51 let x: *i64 = bf_new()
52 bf_set_int(x, j)
53 x[0] = x[0] - 3
54 return bf_atan01(out, x)
55 }
56 let eightb: *i64 = bf_new()
57 bf_set_int(eightb, 8)
58 let inv: *i64 = bf_new()
59 bf_div_small(inv, eightb, j) // 8/j < 1
60 let s: *i64 = bf_new()
61 bf_atan01(s, inv)
62 let p2: *i64 = bf_new()
63 bf_pi(p2)
64 p2[0] = p2[0] - 1
65 return bf_sub(out, p2, s)
66}
67
68// split a positive bigfloat into f64 hi + signed f64 lo; writes both rows
69func mat_emit_hilo(fd: i64, idxhi: i64, idxlo: i64, a: *i64) -> i64 {
70 if bf_is_zero(a) == 1 {
71 mat_emit_row(fd, idxhi, 0)
72 mat_emit_row(fd, idxlo, 0)
73 return 0
74 }
75 let hi: i64 = bf_to_f64(a, 0, 0)
76 let hib: *i64 = bf_new()
77 bf_set_f64(hib, hi)
78 let rem: *i64 = bf_new()
79 var losig: i64 = 0
80 if bf_cmp(a, hib) >= 0 {
81 bf_sub(rem, a, hib)
82 } else {
83 bf_sub(rem, hib, a)
84 losig = 1
85 }
86 mat_emit_row(fd, idxhi, hi)
87 mat_emit_row(fd, idxlo, bf_to_f64(rem, losig, 0))
88 return 0
89}
90
91func main() -> i64 {
92 let fd: i64 = sys_openat_wr("runtime/_hdl_build/_pm_atan_spec.nx" as *u8, 0x1a4)
93 if fd < 0 { sys_exit(2) }
94 pe_w(fd, "// _pm_atan_spec.nx -- GENERATED by nx_mathspec_atan (SOVEREIGN bigfloat,\n" as *u8)
95 pe_w(fd, "// no python). DO NOT HAND-EDIT. Layout: see nx_mathspec_atan.nx header.\n" as *u8)
96 pe_w(fd, "import \"nx_syscalls.nx\"\n\nfunc pm_atan_spec_fill(c: *i64) -> i64 {\n" as *u8)
97
98 let one: *i64 = bf_new()
99 bf_set_int(one, 1)
100 mat_emit_row(fd, 0, bf_to_f64(one, 0, 0))
101 let half: *i64 = bf_new()
102 bf_copy(half, one)
103 half[0] = half[0] - 1
104 mat_emit_row(fd, 1, bf_to_f64(half, 0, 0))
105 let eightb: *i64 = bf_new()
106 bf_set_int(eightb, 8)
107 mat_emit_row(fd, 2, bf_to_f64(eightb, 0, 0))
108
109 let p2: *i64 = bf_new()
110 bf_pi(p2)
111 p2[0] = p2[0] - 1
112 mat_emit_hilo(fd, 3, 4, p2)
113
114 let cut: *i64 = bf_new()
115 bf_set_int(cut, 41)
116 cut[0] = cut[0] - 4 // 41/16 = 2.K_MAGIC_5625
117 mat_emit_row(fd, 5, bf_to_f64(cut, 0, 0))
118
119 // anchors c_j = j/8 (exact in f64)
120 var j: i64 = 0
121 while j <= 20 {
122 if j == 0 {
123 mat_emit_row(fd, 6, 0)
124 } else {
125 let cj: *i64 = bf_new()
126 bf_set_int(cj, j)
127 cj[0] = cj[0] - 3
128 mat_emit_row(fd, 6 + j, bf_to_f64(cj, 0, 0))
129 }
130 j = j + 1
131 }
132
133 // A_hi / A_lo tables
134 j = 0
135 while j <= 20 {
136 let aj: *i64 = bf_new()
137 mat_atan_j8(aj, j)
138 mat_emit_hilo(fd, 27 + j, 48 + j, aj)
139 j = j + 1
140 }
141
142 // poly coeffs hi-first: k = 7..0, coeff = (-1)^k / (2k+1)
143 var k: i64 = 7
144 var idx: i64 = 69
145 while k >= 0 {
146 let cf: *i64 = bf_new()
147 bf_div_small(cf, one, 2 * k + 1)
148 var bits: i64 = bf_to_f64(cf, 0, 0)
149 if (k & 1) == 1 { bits = bits | (1 << 63) }
150 mat_emit_row(fd, idx, bits)
151 idx = idx + 1
152 k = k - 1
153 }
154
155 pe_w(fd, " return 77\n}\n" as *u8)
156 sys_close(fd)
157 pe_w(1, "SPEC EMITTED: _pm_atan_spec.nx (77 consts, all from sovereign bigfloat atan)\n" as *u8)
158 sys_exit(0)
159 return 0
160}