package strconv import "decimal" Decimal_Slice :: struct { digits: []byte, count: int, decimal_point: int, neg: bool, } Float_Info :: struct { mantbits: uint, expbits: uint, bias: int, } _f16_info := Float_Info{10, 5, -15} _f32_info := Float_Info{23, 8, -127} _f64_info := Float_Info{52, 11, -1023} generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte { bits: u64 flt: ^Float_Info switch bit_size { case 16: bits = u64(transmute(u16)f16(val)) flt = &_f16_info case 32: bits = u64(transmute(u32)f32(val)) flt = &_f32_info case 64: bits = transmute(u64)val flt = &_f64_info case: panic("strconv: invalid bit_size") } neg := bits>>(flt.expbits+flt.mantbits) != 0 exp := int(bits>>flt.mantbits) & (1< []byte { Buffer :: struct { b: []byte, n: int, } to_bytes :: proc(b: Buffer) -> []byte { return b.b[:b.n] } add_bytes :: proc(buf: ^Buffer, bytes: ..byte) { buf.n += copy(buf.b[buf.n:], bytes) } b := Buffer{b = buf} prec := precision switch fmt { case 'f', 'F': add_bytes(&b, '-' if neg else '+') // integer, padded with zeros when needed if digs.decimal_point > 0 { m := min(digs.count, digs.decimal_point) add_bytes(&b, ..digs.digits[0:m]) for ; m < digs.decimal_point; m += 1 { add_bytes(&b, '0') } } else { add_bytes(&b, '0') } // fractional part if prec > 0 { add_bytes(&b, '.') for i in 0.. 0 { add_bytes(&b, '.') i := 1 m := min(digs.count, prec+1) if i < m { add_bytes(&b, ..digs.digits[i:m]) i = m } for ; i <= prec; i += 1 { add_bytes(&b, '0') } } add_bytes(&b, fmt) exp := digs.decimal_point-1 if digs.count == 0 { // Zero has exponent of 0 exp = 0 } ch = '+' if exp < 0 { ch = '-' exp = -exp } add_bytes(&b, ch) switch { case exp < 10: add_bytes(&b, '0', byte(exp)+'0') // add prefix 0 case exp < 100: add_bytes(&b, byte(exp/10)+'0', byte(exp%10)+'0') case: add_bytes(&b, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0') } return to_bytes(b) case 'g', 'G': eprec := prec if eprec > digs.count && digs.count >= digs.decimal_point { eprec = digs.count } if shortest { eprec = 6 } exp := digs.decimal_point - 1 if exp < -4 || exp >= eprec { if prec > digs.count { prec = digs.count } return format_digits(buf, shortest, neg, digs, prec-1, fmt+'e'-'g') // keep the same case } if prec > digs.decimal_point { prec = digs.count } return format_digits(buf, shortest, neg, digs, max(prec-digs.decimal_point, 0), 'f') case: add_bytes(&b, '%', fmt) return to_bytes(b) } } round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Info) { if mant == 0 { // If mantissa is zero, the number is zero d.count = 0 return } /* 10^(dp-nd) > 2^(exp-mantbits) log2(10) * (dp-nd) > exp-mantbits log(2) >~ 0.332 332*(dp-nd) >= 100*(exp-mantbits) */ minexp := flt.bias+1 if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) { // Number is already its shortest return } upper_: decimal.Decimal; upper := &upper_ decimal.assign(upper, 2*mant - 1) decimal.shift(upper, exp - int(flt.mantbits) - 1) mantlo: u64 explo: int if mant > 1<