///|
fn numeric_text(s : String) -> Bool {
let cs = s
let mut i = 0
if !cs.is_empty() && cs[0] == 45 {
i += 1
}
let start = i
while i < cs.length() && cs[i] >= 48 && cs[i] <= 57 {
i += 1
}
let before = i - start
if i < cs.length() && cs[i] == 46 {
i += 1
let start = i
while i < cs.length() && cs[i] >= 48 && cs[i] <= 57 {
i += 1
}
if i == start && before == 0 {
return false
}
} else if before == 0 {
return false
}
if i < cs.length() && (cs[i] == 101 || cs[i] == 69) {
i += 1
if i < cs.length() && (cs[i] == 43 || cs[i] == 45) {
i += 1
}
let start = i
while i < cs.length() && cs[i] >= 48 && cs[i] <= 57 {
i += 1
}
if i == start {
return false
}
}
i == cs.length()
}
///|
// Exact significand rounding also handles hexadecimal subnormal boundary values.
fn hex_double(text : String) -> Double raise ParseError {
let cs = text.to_array()
let mut i = 2
let mut dotted = false
let mut fraction = 0
let mut count = 0
let mut significand = @bigint.BigInt::from_int(0)
while i < cs.length() {
let c = cs[i]
if c == '.' && !dotted {
dotted = true
i += 1
continue
}
let n = if c >= '0' && c <= '9' {
c.to_int() - 48
} else if c >= 'a' && c <= 'f' {
c.to_int() - 87
} else if c >= 'A' && c <= 'F' {
c.to_int() - 55
} else {
break
}
significand = (significand << 4) + @bigint.BigInt::from_int(n)
count += 1
if dotted {
fraction += 1
}
i += 1
}
if count == 0 || i >= cs.length() || !(cs[i] == 'p' || cs[i] == 'P') {
raise Invalid("invalid hexadecimal number")
}
i += 1
let negative = i < cs.length() && cs[i] == '-'
if i < cs.length() && (cs[i] == '+' || cs[i] == '-') {
i += 1
}
let begin = i
let mut power = 0
while i < cs.length() && cs[i] >= '0' && cs[i] <= '9' {
power = (power * 10 + cs[i].to_int() - 48).min(1000000)
i += 1
}
if i != cs.length() || i == begin {
raise Invalid("invalid hexadecimal exponent")
}
let exponent = (if negative { -power } else { power }) - fraction * 4
let bits = significand.bit_length()
if bits == 0 {
return 0.0
}
let high = bits - 1 + exponent
if high > 1023 {
return 1.0 / 0.0
}
if high < -1075 {
return 0.0
}
let shift = (bits - 53).max(-1074 - exponent).max(0)
let mut rounded = significand >> shift
if shift > 0 {
let lost = significand - (rounded << shift)
let half = @bigint.BigInt::from_int(1) << (shift - 1)
if lost > half || (lost == half && rounded.to_int64() % 2L == 1L) {
rounded = rounded + @bigint.BigInt::from_int(1)
}
}
@math.scalbn(rounded.to_int64().to_double(), exponent + shift)
}