code wiki / (root) / nx_js_f64.nx

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}