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} /* Converts a floating-point number to a string with the specified format and precision. **Inputs** buf: A byte slice to store the resulting string val: The floating-point value to be converted fmt: The formatting byte, accepted values are 'e', 'E', 'f', 'F', 'g', 'G' precision: The number of decimal places to round to bit_size: The size of the floating-point number in bits, valid values are 16, 32, 64 Example: buf: [32]byte val := 3.141592 fmt := 'f' precision := 2 bit_size := 64 result := strconv.generic_ftoa(buf[:], val, fmt, precision, bit_size) -> "3.14" **Returns** - A byte slice containing the formatted string */ 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) } } /* Rounds the given decimal number to its shortest representation, considering the provided floating-point format **Inputs** - d: The decimal number to round - mant: The mantissa of the floating-point number - exp: The exponent of the floating-point number - flt: Pointer to the Float_Info structure containing information about the floating-point format */ 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< (b: u64, overflow: bool) { end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) { bits = mant & (u64(1)< bool { mant^ = 0 exp^ = 1< 310 { set_overflow(&mant, &exp, info) b = end(d, mant, exp, info) return } else if d.decimal_point < -330 { mant = 0 exp = info.bias b = end(d, mant, exp, info) return } @static power_table := [?]int{1, 3, 6, 9, 13, 16, 19, 23, 26} exp = 0 for d.decimal_point > 0 { n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point] decimal.shift(d, -n) exp += n } for d.decimal_point < 0 || d.decimal_point == 0 && d.digits[0] < '5' { n := 27 if -d.decimal_point >= len(power_table) else power_table[-d.decimal_point] decimal.shift(d, n) exp -= n } // go from [0.5, 1) to [1, 2) exp -= 1 if exp < info.bias + 1 { n := info.bias + 1 - exp decimal.shift(d, n) exp += n } if (exp-info.bias) >= (1<>= 1 exp += 1 if (exp-info.bias) >= (1<