blob: 2a34e8d0796a04b1f4731eefe17031c2f18be61d [file] [log] [blame]
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Decimal to binary floating point conversion.
// Algorithm:
// 1) Store input in multiprecision decimal.
// 2) Multiply/divide decimal by powers of two until in range [0.5, 1)
// 3) Multiply by 2^precision and round to get mantissa.
package strconv
import "strconv"
// TODO(rsc): Better truncation handling, check for overflow in exponent.
func StringToDecimal(s string) (neg bool, d *Decimal, trunc bool, ok bool) {
i := 0;
// optional sign
if i >= len(s) {
return;
}
switch {
case s[i] == '+':
i++;
case s[i] == '-':
neg = true;
i++;
}
// digits
b := new(Decimal);
sawdot := false;
sawdigits := false;
for ; i < len(s); i++ {
switch {
case s[i] == '.':
if sawdot {
return;
}
sawdot = true;
b.dp = b.nd;
continue;
case '0' <= s[i] && s[i] <= '9':
sawdigits = true;
if s[i] == '0' && b.nd == 0 { // ignore leading zeros
b.dp--;
continue;
}
b.d[b.nd] = s[i];
b.nd++;
continue;
}
break;
}
if !sawdigits {
return;
}
if !sawdot {
b.dp = b.nd;
}
// optional exponent moves decimal point
if i < len(s) && s[i] == 'e' {
i++;
if i >= len(s) {
return;
}
esign := 1;
if s[i] == '+' {
i++;
} else if s[i] == '-' {
i++;
esign = -1;
}
if i >= len(s) || s[i] < '0' || s[i] > '9' {
return;
}
e := 0;
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
e = e*10 + int(s[i]) - '0';
}
b.dp += e*esign;
}
if i != len(s) {
return;
}
d = b;
ok = true;
return;
}
// Decimal power of ten to binary power of two.
var powtab = []int{
1, 3, 6, 9, 13, 16, 19, 23, 26
}
func DecimalToFloatBits(neg bool, d *Decimal, trunc bool, flt *FloatInfo) (b uint64, overflow bool) {
// Zero is always a special case.
if d.nd == 0 {
return 0, false
}
// TODO: check for obvious overflow
// Scale by powers of two until in range [0.5, 1.0)
exp := 0;
for d.dp > 0 {
var n int;
if d.dp >= len(powtab) {
n = 27;
} else {
n = powtab[d.dp];
}
d.Shift(-n);
exp += n;
}
for d.dp < 0 || d.dp == 0 && d.d[0] < '5' {
var n int;
if -d.dp >= len(powtab) {
n = 27;
} else {
n = powtab[-d.dp];
}
d.Shift(n);
exp -= n;
}
// Our range is [0.5,1) but floating point range is [1,2).
exp--;
// Minimum representable exponent is flt.bias+1.
// If the exponent is smaller, move it up and
// adjust d accordingly.
if exp < flt.bias+1 {
n := flt.bias+1 - exp;
d.Shift(-n);
exp += n;
}
// TODO: overflow/underflow
// Extract 1+flt.mantbits bits.
mant := d.Shift(int(1+flt.mantbits)).RoundedInteger();
// Denormalized?
if mant&(1<<flt.mantbits) == 0 {
if exp != flt.bias+1 {
// TODO: remove - has no business panicking
panicln("DecimalToFloatBits", exp, flt.bias+1);
}
exp--;
} else {
if exp <= flt.bias {
// TODO: remove - has no business panicking
panicln("DecimalToFloatBits1", exp, flt.bias);
}
}
// Assemble bits.
bits := mant & (uint64(1)<<flt.mantbits - 1);
bits |= uint64((exp-flt.bias)&(1<<flt.expbits - 1)) << flt.mantbits;
if neg {
bits |= 1<<flt.mantbits<<flt.expbits;
}
return bits, false;
}
// If possible to convert decimal d to 64-bit float f exactly,
// entirely in floating-point math, do so, avoiding the machinery above.
func DecimalToFloat64(neg bool, d *Decimal, trunc bool) (f float64, ok bool) {
// TODO: Fill in.
return 0, false;
}
// If possible to convert decimal d to 32-bit float f exactly,
// entirely in floating-point math, do so, avoiding the machinery above.
func DecimalToFloat32(neg bool, d *Decimal, trunc bool) (f float32, ok bool) {
// TODO: Fill in.
return 0, false;
}
export func atof64(s string) (f float64, overflow bool, ok bool) {
neg, d, trunc, ok1 := StringToDecimal(s);
if !ok1 {
return 0, false, false;
}
if f, ok := DecimalToFloat64(neg, d, trunc); ok {
return f, false, true;
}
b, overflow1 := DecimalToFloatBits(neg, d, trunc, &float64info);
return sys.float64frombits(b), overflow1, true;
}
export func atof32(s string) (f float32, overflow bool, ok bool) {
neg, d, trunc, ok1 := StringToDecimal(s);
if !ok1 {
return 0, false, false;
}
if f, ok := DecimalToFloat32(neg, d, trunc); ok {
return f, false, true;
}
b, overflow1 := DecimalToFloatBits(neg, d, trunc, &float32info);
return sys.float32frombits(uint32(b)), overflow1, true;
}
export func atof(s string) (f float, overflow bool, ok bool) {
if floatsize == 32 {
var f1 float32;
f1, overflow, ok = atof32(s);
return float(f1), overflow, ok;
}
var f1 float64;
f1, overflow, ok = atof64(s);
return float(f1), overflow, ok;
}