code wiki / (root) / nx_f64_div.nx

nx_f64_div.nx source

↩ module page · 96 lines · 3345 B

1// nx_f64_div.nx -- IEEE 754 binary64 division (standalone file). 2// 3// Separate from nx_f64.nx mirroring the f32 family split (same-file mul+div 4// codegen quirk, see nx_f32_div.nx header). 5// 6// CORRECTNESS BAR: unlike f32 v1 (which zeroed subnormal operands and lost 7// the guard bit in the sig_a < sig_b case), this is correctly rounded RNE 8// over the full domain: subnormal operands pre-normalize, the restoring 9// division produces 56 quotient bits + exact remainder, guard is explicit 10// in both alignment cases, sticky = remainder nonzero. 11// 12// Restoring division: q = floor(sig_a * 2^55 / sig_b) bit-serial. 13// Working values: r < 2^54 before doubling, < 2^55 after; q < 2^56. 14// Everything fits i64 with headroom (probe-verified arithmetic). 15// 16// license_tier: ORIGINAL 17 18import "nx_syscalls.nx" 19import "nx_tier.nx" 20import "nx_f64.nx" 21 22func nx_f64_div(a: i64, b: i64) -> i64 { 23 let cls_a: nx_int = nx_f64_classify(a) 24 let cls_b: nx_int = nx_f64_classify(b) 25 let sign_out: i64 = nx_f64_sign(a) ^ nx_f64_sign(b) 26 27 if cls_a == NX_F64_CLS_NAN { return NX_F64_NAN_RAW } 28 if cls_b == NX_F64_CLS_NAN { return NX_F64_NAN_RAW } 29 30 if cls_b == NX_F64_CLS_ZERO { 31 if cls_a == NX_F64_CLS_ZERO { return NX_F64_NAN_RAW } 32 return (sign_out << 63) | NX_F64_INF_RAW // x/0 = inf (incl. inf/0) 33 } 34 if cls_b == NX_F64_CLS_INF { 35 if cls_a == NX_F64_CLS_INF { return NX_F64_NAN_RAW } 36 return sign_out << 63 // finite/inf = 0 37 } 38 if cls_a == NX_F64_CLS_ZERO { return sign_out << 63 } 39 if cls_a == NX_F64_CLS_INF { 40 return (sign_out << 63) | NX_F64_INF_RAW 41 } 42 43 // Significands pre-normalized to [2^52, 2^53); subnormal exponents go 44 // negative and _f64_round_pack denormalizes the result back. 45 var sig_a: i64 = nx_f64_mant_field(a) 46 var exp_a: i64 = nx_f64_exp_field(a) 47 if exp_a == 0 { 48 exp_a = 1 49 while sig_a < NX_F64_IMPLICIT_1 { sig_a = sig_a << 1; exp_a = exp_a - 1 } 50 } else { 51 sig_a = sig_a | NX_F64_IMPLICIT_1 52 } 53 var sig_b: i64 = nx_f64_mant_field(b) 54 var exp_b: i64 = nx_f64_exp_field(b) 55 if exp_b == 0 { 56 exp_b = 1 57 while sig_b < NX_F64_IMPLICIT_1 { sig_b = sig_b << 1; exp_b = exp_b - 1 } 58 } else { 59 sig_b = sig_b | NX_F64_IMPLICIT_1 60 } 61 62 // q = floor(sig_a * 2^55 / sig_b), r = exact remainder. 63 var q: i64 = 0 64 var r: i64 = sig_a 65 if r >= sig_b { q = 1; r = r - sig_b } 66 var i: i64 = 0 67 while i < 55 { 68 r = r << 1 69 q = q << 1 70 if r >= sig_b { q = q + 1; r = r - sig_b } 71 i = i + 1 72 } 73 74 // sig_a/sig_b in (1/2, 2) so q in (2^54, 2^56). 75 var mant_out: i64 = 0 76 var guard: i64 = 0 77 var sticky: i64 = 0 78 var eo: i64 = 0 79 if q >= (1 << 55) { 80 // Ratio in [1,2): top 53 bits = q >> 3. 81 mant_out = q >> 3 82 guard = (q >> 2) & 1 83 if (q & 3) != 0 { sticky = 1 } 84 if r != 0 { sticky = 1 } 85 eo = exp_a - exp_b + NX_F64_EXP_BIAS 86 } else { 87 // Ratio in (1/2, 1): top 53 bits = q >> 2, exponent one lower. 88 mant_out = q >> 2 89 guard = (q >> 1) & 1 90 if (q & 1) != 0 { sticky = 1 } 91 if r != 0 { sticky = 1 } 92 eo = exp_a - exp_b + NX_F64_EXP_BIAS - 1 93 } 94 95 return _f64_round_pack(sign_out, eo, mant_out, guard, sticky) 96}