nx_js_f64.nx source
↩ module page · 136 lines · 5281 B
1// nx_js_f64.nx -- JS Number (f64) <-> i64 / decimal-string converters for the sovereign JS engine.
2// WB-JS-001 rung R-JS-F64-0/1 (the foundation of f64 JS numbers). NishiLang f64 is software-IEEE: a
3// value IS its 64-bit pattern held in an i64. This organ composes the gated nx_f64 soft-float kernels
4// to add the int<->f64 and string<->f64 conversions that nx_f64 lacks. LIBRARY (no main) -- the gate
5// lives in nx_js_f64_test.nx so nx_js_eval can import this without a two-main build conflict. The
6// engine integration (VAL_FLOAT, float literals, arithmetic) is rung R-JS-F64-2 in nx_js_eval.
7// license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_f64.nx"
10import "nx_f64_div.nx"
11
12const F64_ONE: i64 = 0x3FF0000000000000 // 1.0
13const F64_TEN: i64 = 0x4024000000000000 // 10.0
14const MANT52: i64 = 0x000FFFFFFFFFFFFF
15const IMPL1: i64 = 0x0010000000000000 // implicit 1 at bit 52
16
17// i64 -> f64 bits. Exact for |n| < 2^53 (low bits dropped without rounding above that -- named limit).
18func ji2f(n: i64) -> i64 {
19 if n == 0 { return 0 }
20 var neg: i64 = 0
21 var m: i64 = n
22 if m < 0 { neg = 1; m = 0 - m }
23 var bl: i64 = 0 // bit length of m
24 var t: i64 = m
25 while t > 0 { bl = bl + 1; t = t >> 1 }
26 let e: i64 = (bl - 1) + 1023 // biased exponent
27 let shift: i64 = 52 - (bl - 1) // align MSB to bit 52
28 var mant: i64 = 0
29 if shift >= 0 { mant = (m << shift) & MANT52 }
30 else { mant = (m >> (0 - shift)) & MANT52 }
31 let raw: i64 = (e << 52) | mant
32 if neg == 1 { return nx_f64_neg(raw) }
33 return raw
34}
35
36// f64 bits -> i64, truncating toward zero. zero/inf/nan/|x|<1 -> 0.
37func jf2i(raw: i64) -> i64 {
38 let cls: i64 = nx_f64_classify(raw)
39 if cls == 0 { return 0 } // zero
40 if cls == 3 { return 0 } // inf (honest stub)
41 if cls == 4 { return 0 } // nan
42 let e: i64 = nx_f64_exp_field(raw) - 1023
43 if e < 0 { return 0 } // |x| < 1
44 let mant: i64 = nx_f64_mant_field(raw) | IMPL1
45 var v: i64 = 0
46 let shift: i64 = e - 52
47 if shift >= 0 { v = mant << shift }
48 else { v = mant >> (0 - shift) }
49 if nx_f64_sign(raw) == 1 { return 0 - v }
50 return v
51}
52
53// 10^k as f64 bits (k>=0). Exact for k <= 22.
54func jpow10(k: i64) -> i64 {
55 var r: i64 = F64_ONE
56 var i: i64 = 0
57 while i < k { r = nx_f64_mul(r, F64_TEN); i = i + 1 }
58 return r
59}
60
61// parse a plain decimal [sign]int[.frac] -> f64 bits. (e/E exponent notation = a follow-on rung.)
62// Builds the digit string as an integer mantissa, then DIVIDES by an exact 10^fdig.
63func jparse_f64(src: *u8, len: i64) -> i64 {
64 var i: i64 = 0
65 var neg: i64 = 0
66 if i < len {
67 if (src[i] & 0xff) == 45 { neg = 1; i = i + 1 }
68 else { if (src[i] & 0xff) == 43 { i = i + 1 } }
69 }
70 var mant: i64 = 0
71 var fdig: i64 = 0
72 var seen_dot: i64 = 0
73 var go: i64 = 1
74 while go == 1 {
75 if i >= len { go = 0 }
76 else {
77 let c: i64 = src[i] & 0xff
78 if c == 46 { seen_dot = 1; i = i + 1 }
79 else {
80 if c < 48 { go = 0 }
81 else { if c > 57 { go = 0 }
82 else {
83 mant = mant * 10 + (c - 48)
84 if seen_dot == 1 { fdig = fdig + 1 }
85 i = i + 1
86 } }
87 }
88 }
89 }
90 var f: i64 = ji2f(mant)
91 if fdig > 0 { f = nx_f64_div(f, jpow10(fdig)) }
92 if neg == 1 { return nx_f64_neg(f) }
93 return f
94}
95
96// f64 bits -> decimal string into out (no NUL); returns length. Exact-representable decimals format
97// EXACTLY (0.5->"0.5", 3.0->"3", 0.125->"0.125"); inexact values cap at 17 frac digits (NOT yet
98// shortest-round-trip dtoa -- a named follow-on). zero->"0", negatives get '-', inf/nan handled.
99func jf64_to_str(raw: i64, out: *u8) -> i64 {
100 var p: i64 = 0
101 let cls: i64 = nx_f64_classify(raw)
102 if cls == 0 { out[0] = 48; return 1 } // "0"
103 if cls == 4 { out[0]=78; out[1]=97; out[2]=78; return 3 } // "NaN"
104 if nx_f64_sign(raw) == 1 { out[p] = 45; p = p + 1 } // '-'
105 let a: i64 = nx_f64_abs(raw)
106 if cls == 3 { // Infinity
107 let inf: *u8 = "Infinity\x00" as *u8
108 var j2: i64 = 0
109 while inf[j2] != (0 as u8) { out[p] = inf[j2]; p = p + 1; j2 = j2 + 1 }
110 return p
111 }
112 let ip: i64 = jf2i(a)
113 let dt: *u8 = sys_mmap(28)
114 var k: i64 = 0
115 var m: i64 = ip
116 if m == 0 { dt[0] = 48; k = 1 }
117 while m > 0 { dt[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
118 var j: i64 = 0
119 while j < k { out[p] = dt[k - 1 - j]; p = p + 1; j = j + 1 }
120 var frac: i64 = nx_f64_add(a, nx_f64_neg(ji2f(ip)))
121 if nx_f64_is_zero(frac) == 0 {
122 out[p] = 46; p = p + 1 // '.'
123 var cnt: i64 = 0
124 while cnt < 17 {
125 if nx_f64_is_zero(frac) == 1 { cnt = 17 }
126 else {
127 let f10: i64 = nx_f64_mul(frac, F64_TEN)
128 let d: i64 = jf2i(f10)
129 out[p] = (48 + d) as u8; p = p + 1
130 frac = nx_f64_add(f10, nx_f64_neg(ji2f(d)))
131 cnt = cnt + 1
132 }
133 }
134 }
135 return p
136}