File: ftostr.go

package info (click to toggle)
golang-github-dop251-goja 0.0~git20250630.0.58d95d8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,264 kB
  • sloc: javascript: 454; perl: 184; makefile: 6; sh: 1
file content (147 lines) | stat: -rw-r--r-- 3,389 bytes parent folder | download
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/dop251/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
}