Skip to content

Commit

Permalink
proper exp syntax support for decimals
Browse files Browse the repository at this point in the history
  • Loading branch information
PgBiel committed Oct 17, 2024
1 parent d688fb6 commit b2427cd
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 7 deletions.
46 changes: 41 additions & 5 deletions oxifmt.typ
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,48 @@
assert(_strfmt_is-numeric-type(num), message: "String formatter internal error: Cannot convert '" + repr(num) + "' to a number to obtain its scientific notation representation.")

if type(num) == _decimal {
// TODO: 0.000X support
// Normalize signed zero
let num = if num == 0 { _decimal("0") } else { num }
let (integral, ..fractional) = str(num).split(".")
let fractional = fractional.join()
let total-digits = integral.len() + fractional.len()
let mantissa = integral.codepoints().first() + "." + integral.slice(1) + fractional
return (mantissa, exponent-sign + _strfmt_stringify(total-digits - 1))
// Normalize decimals with larger scales than is needed
let fractional = fractional.sum(default: "").trim("0", at: end)
let (integral, fractional, exponent) = if num > -1 and num < 1 and fractional != "" {
let first-non-zero = fractional.position("1")
if first-non-zero == none { first-non-zero = fractional.position("2") }
if first-non-zero == none { first-non-zero = fractional.position("3") }
if first-non-zero == none { first-non-zero = fractional.position("4") }
if first-non-zero == none { first-non-zero = fractional.position("5") }
if first-non-zero == none { first-non-zero = fractional.position("6") }
if first-non-zero == none { first-non-zero = fractional.position("7") }
if first-non-zero == none { first-non-zero = fractional.position("8") }
if first-non-zero == none { first-non-zero = fractional.position("9") }
assert(first-non-zero != none, message: "String formatter internal error: expected non-zero fractional digit")

// Integral part is zero
// Convert 0.00012345 -> 1.2345
// Position of first non-zero is the amount of zeroes - 1
// (e.g. above, position of 1 is 3 => 3 zeroes,
// so exponent is -3 - 1 = -4)
(
fractional.at(first-non-zero),
fractional.slice(first-non-zero + 1),
-first-non-zero - 1
)
} else {
// Number has non-zero integral part, or is zero
// Convert 12345.6789 -> 1.23456789
// Exponent is integral digits - 1
(
integral.at(0),
integral.slice(1) + fractional,
integral.len() - 1
)
}
return (
// mantissa
integral + if fractional != "" { "." + fractional } else { "" },
exponent-sign + _strfmt_stringify(exponent)
)
}

let f = float(num)
Expand Down
7 changes: 5 additions & 2 deletions tests/strfmt-tests.typ
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,11 @@
assert.eq(strfmt("{}", decimal("-1223.435032"), fmt-thousands-separator: "_"), "-1_223.435032")
assert.eq(strfmt("{:+09}", decimal("1234.5")), "+001234.5")
assert.eq(strfmt("{:+09}", decimal("1234.5"), fmt-thousands-separator: "_"), "+001_234.5")
assert.eq(strfmt("{:011e}", -decimal("1234.5")), "-001.2345e4")
assert.eq(strfmt("{:011e}", -decimal("1234.50000")), "-001.2345e4")
assert.eq(strfmt("{:011e}", -decimal("1234.5")), "-001.2345e3")
assert.eq(strfmt("{:011e}", -decimal("1234.50000")), "-001.2345e3")
assert.eq(strfmt("{:011e}", -decimal("0.00012345")), "-01.2345e-4")
assert.eq(strfmt("{:e}", -decimal("0")), "0e0")
assert.eq(strfmt("{:e}", decimal("132423")), "1.32423e5")
assert.eq(strfmt("{:011.5}", decimal("1234.5")), "01234.50000")
}
// DOC TESTS
Expand Down

0 comments on commit b2427cd

Please sign in to comment.