forked from dop251/goja
/
ftostr.go
147 lines (133 loc) · 3.32 KB
/
ftostr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package ftoa
import (
"math"
"strconv"
"github.com/AnxiangLemon/goja/ftoa/internal/fast"
)
type FToStrMode int
const (
// Either fixed or exponential format; round-trip
ModeStandard FToStrMode = iota
// Always exponential format; round-trip
ModeStandardExponential
// Round to <precision> digits after the decimal point; exponential if number is large
ModeFixed
// Always exponential format; <precision> significant digits
ModeExponential
// Either fixed or exponential format; <precision> significant digits
ModePrecision
)
func insert(b []byte, p int, c byte) []byte {
b = append(b, 0)
copy(b[p+1:], b[p:])
b[p] = c
return b
}
func expand(b []byte, delta int) []byte {
newLen := len(b) + delta
if newLen <= cap(b) {
return b[:newLen]
}
b1 := make([]byte, newLen)
copy(b1, b)
return b1
}
func FToStr(d float64, mode FToStrMode, precision int, buffer []byte) []byte {
if math.IsNaN(d) {
buffer = append(buffer, "NaN"...)
return buffer
}
if math.IsInf(d, 0) {
if math.Signbit(d) {
buffer = append(buffer, '-')
}
buffer = append(buffer, "Infinity"...)
return buffer
}
if mode == ModeFixed && (d >= 1e21 || d <= -1e21) {
mode = ModeStandard
}
var decPt int
var ok bool
startPos := len(buffer)
if d != 0 { // also matches -0
if d < 0 {
buffer = append(buffer, '-')
d = -d
startPos++
}
switch mode {
case ModeStandard, ModeStandardExponential:
buffer, decPt, ok = fast.Dtoa(d, fast.ModeShortest, 0, buffer)
case ModeExponential, ModePrecision:
buffer, decPt, ok = fast.Dtoa(d, fast.ModePrecision, precision, buffer)
}
} else {
buffer = append(buffer, '0')
decPt, ok = 1, true
}
if !ok {
buffer, decPt = ftoa(d, dtoaModes[mode], mode >= ModeFixed, precision, buffer)
}
exponentialNotation := false
minNDigits := 0 /* Minimum number of significand digits required by mode and precision */
nDigits := len(buffer) - startPos
switch mode {
case ModeStandard:
if decPt < -5 || decPt > 21 {
exponentialNotation = true
} else {
minNDigits = decPt
}
case ModeFixed:
if precision >= 0 {
minNDigits = decPt + precision
} else {
minNDigits = decPt
}
case ModeExponential:
// JS_ASSERT(precision > 0);
minNDigits = precision
fallthrough
case ModeStandardExponential:
exponentialNotation = true
case ModePrecision:
// JS_ASSERT(precision > 0);
minNDigits = precision
if decPt < -5 || decPt > precision {
exponentialNotation = true
}
}
for nDigits < minNDigits {
buffer = append(buffer, '0')
nDigits++
}
if exponentialNotation {
/* Insert a decimal point if more than one significand digit */
if nDigits != 1 {
buffer = insert(buffer, startPos+1, '.')
}
buffer = append(buffer, 'e')
if decPt-1 >= 0 {
buffer = append(buffer, '+')
}
buffer = strconv.AppendInt(buffer, int64(decPt-1), 10)
} else if decPt != nDigits {
/* Some kind of a fraction in fixed notation */
// JS_ASSERT(decPt <= nDigits);
if decPt > 0 {
/* dd...dd . dd...dd */
buffer = insert(buffer, startPos+decPt, '.')
} else {
/* 0 . 00...00dd...dd */
buffer = expand(buffer, 2-decPt)
copy(buffer[startPos+2-decPt:], buffer[startPos:])
buffer[startPos] = '0'
buffer[startPos+1] = '.'
for i := startPos + 2; i < startPos+2-decPt; i++ {
buffer[i] = '0'
}
}
}
return buffer
}