mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 08:08:50 +00:00
%e and %g support in fmt.printf
This commit is contained in:
@@ -130,10 +130,15 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shift_left :: proc(a: ^Decimal, k: uint) {
|
shift_left :: proc(a: ^Decimal, k: uint) {
|
||||||
delta := int(k/4);
|
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
|
||||||
|
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
|
||||||
|
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310;
|
||||||
|
capacity := int(f64(k)*log10_2 + 1);
|
||||||
|
|
||||||
r := a.count; // read index
|
r := a.count; // read index
|
||||||
w := a.count+delta; // write index
|
w := a.count+capacity; // write index
|
||||||
|
|
||||||
|
d := len(a.digits);
|
||||||
|
|
||||||
n: uint;
|
n: uint;
|
||||||
for r -= 1; r >= 0; r -= 1 {
|
for r -= 1; r >= 0; r -= 1 {
|
||||||
@@ -141,7 +146,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
|||||||
quo := n/10;
|
quo := n/10;
|
||||||
rem := n - 10*quo;
|
rem := n - 10*quo;
|
||||||
w -= 1;
|
w -= 1;
|
||||||
if w < len(a.digits) {
|
if w < d {
|
||||||
a.digits[w] = byte('0' + rem);
|
a.digits[w] = byte('0' + rem);
|
||||||
} else if rem != 0 {
|
} else if rem != 0 {
|
||||||
a.trunc = true;
|
a.trunc = true;
|
||||||
@@ -153,7 +158,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
|||||||
quo := n/10;
|
quo := n/10;
|
||||||
rem := n - 10*quo;
|
rem := n - 10*quo;
|
||||||
w -= 1;
|
w -= 1;
|
||||||
if 0 <= w && w < len(a.digits) {
|
if w < d {
|
||||||
a.digits[w] = byte('0' + rem);
|
a.digits[w] = byte('0' + rem);
|
||||||
} else if rem != 0 {
|
} else if rem != 0 {
|
||||||
a.trunc = true;
|
a.trunc = true;
|
||||||
@@ -161,9 +166,12 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
|||||||
n = quo;
|
n = quo;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.count += delta;
|
// NOTE(bill): Remove unused buffer size
|
||||||
a.count = min(a.count, len(a.digits));
|
assert(w >= 0);
|
||||||
a.decimal_point += delta;
|
capacity -= w;
|
||||||
|
|
||||||
|
a.count = min(a.count+capacity, d);
|
||||||
|
a.decimal_point += capacity;
|
||||||
trim(a);
|
trim(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,3 +261,4 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
|
|||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-3
@@ -551,9 +551,6 @@ _pad :: proc(fi: ^Info, s: string) {
|
|||||||
|
|
||||||
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
// case 'e', 'E', 'f', 'F', 'g', 'G', 'v':
|
|
||||||
// case 'f', 'F', 'v':
|
|
||||||
|
|
||||||
case 'f', 'F', 'v':
|
case 'f', 'F', 'v':
|
||||||
prec: int = 3;
|
prec: int = 3;
|
||||||
if fi.prec_set do prec = fi.prec;
|
if fi.prec_set do prec = fi.prec;
|
||||||
@@ -588,6 +585,40 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
|||||||
_pad(fi, str[1:]);
|
_pad(fi, str[1:]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'e', 'E':
|
||||||
|
prec: int = 3;
|
||||||
|
if fi.prec_set do prec = fi.prec;
|
||||||
|
buf: [386]byte;
|
||||||
|
|
||||||
|
str := strconv.append_float(buf[1:], v, 'e', prec, bit_size);
|
||||||
|
str = string(buf[:len(str)+1]);
|
||||||
|
if str[1] == '+' || str[1] == '-' {
|
||||||
|
str = str[1:];
|
||||||
|
} else {
|
||||||
|
str[0] = '+';
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.space && !fi.plus && str[0] == '+' {
|
||||||
|
str[0] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(str) > 1 && (str[1] == 'N' || str[1] == 'I') {
|
||||||
|
strings.write_string(fi.buf, str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.plus || str[0] != '+' {
|
||||||
|
if fi.zero && fi.width_set && fi.width > len(str) {
|
||||||
|
strings.write_byte(fi.buf, str[0]);
|
||||||
|
fmt_write_padding(fi, fi.width - len(str));
|
||||||
|
strings.write_string(fi.buf, str[1:]);
|
||||||
|
} else {
|
||||||
|
_pad(fi, str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_pad(fi, str[1:]);
|
||||||
|
}
|
||||||
|
|
||||||
case:
|
case:
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-15
@@ -213,28 +213,28 @@ append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> str
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
DecimalSlice :: struct {
|
Decimal_Slice :: struct {
|
||||||
digits: []byte,
|
digits: []byte,
|
||||||
count: int,
|
count: int,
|
||||||
decimal_point: int,
|
decimal_point: int,
|
||||||
neg: bool,
|
neg: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatInfo :: struct {
|
Float_Info :: struct {
|
||||||
mantbits: uint,
|
mantbits: uint,
|
||||||
expbits: uint,
|
expbits: uint,
|
||||||
bias: int,
|
bias: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_f16_info := FloatInfo{10, 5, -15};
|
_f16_info := Float_Info{10, 5, -15};
|
||||||
_f32_info := FloatInfo{23, 8, -127};
|
_f32_info := Float_Info{23, 8, -127};
|
||||||
_f64_info := FloatInfo{52, 11, -1023};
|
_f64_info := Float_Info{52, 11, -1023};
|
||||||
|
|
||||||
|
|
||||||
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
||||||
bits: u64;
|
bits: u64;
|
||||||
flt: ^FloatInfo;
|
flt: ^Float_Info;
|
||||||
switch bit_size {
|
switch bit_size {
|
||||||
case 32:
|
case 32:
|
||||||
bits = u64(transmute(u32)f32(val));
|
bits = u64(transmute(u32)f32(val));
|
||||||
@@ -276,11 +276,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
|||||||
d := &d_;
|
d := &d_;
|
||||||
assign(d, mant);
|
assign(d, mant);
|
||||||
shift(d, exp - int(flt.mantbits));
|
shift(d, exp - int(flt.mantbits));
|
||||||
digs: DecimalSlice;
|
digs: Decimal_Slice;
|
||||||
shortest := prec < 0;
|
shortest := prec < 0;
|
||||||
if shortest {
|
if shortest {
|
||||||
round_shortest(d, mant, exp, flt);
|
round_shortest(d, mant, exp, flt);
|
||||||
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||||
switch fmt {
|
switch fmt {
|
||||||
case 'e', 'E': prec = digs.count-1;
|
case 'e', 'E': prec = digs.count-1;
|
||||||
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
||||||
@@ -297,14 +297,14 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
|||||||
round(d, prec);
|
round(d, prec);
|
||||||
}
|
}
|
||||||
|
|
||||||
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||||
}
|
}
|
||||||
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: byte) -> []byte {
|
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
|
||||||
Buffer :: struct {
|
Buffer :: struct {
|
||||||
b: []byte,
|
b: []byte,
|
||||||
n: int,
|
n: int,
|
||||||
@@ -347,12 +347,72 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
|
|||||||
return to_bytes(b);
|
return to_bytes(b);
|
||||||
|
|
||||||
case 'e', 'E':
|
case 'e', 'E':
|
||||||
panic("strconv: e/E float printing is not yet supported");
|
add_bytes(&b, neg ? '-' : '+');
|
||||||
return to_bytes(b); // TODO
|
|
||||||
|
ch := byte('0');
|
||||||
|
if digs.count != 0 {
|
||||||
|
ch = digs.digits[0];
|
||||||
|
}
|
||||||
|
add_bytes(&b, ch);
|
||||||
|
|
||||||
|
if prec > 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':
|
case 'g', 'G':
|
||||||
panic("strconv: g/G float printing is not yet supported");
|
eprec := prec;
|
||||||
return to_bytes(b); // TODO
|
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:
|
case:
|
||||||
add_bytes(&b, '%', fmt);
|
add_bytes(&b, '%', fmt);
|
||||||
@@ -362,7 +422,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
|
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||||
if mant == 0 { // If mantissa is zero, the number is zero
|
if mant == 0 { // If mantissa is zero, the number is zero
|
||||||
d.count = 0;
|
d.count = 0;
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user