@@ -3,8 +3,6 @@ package decimal
33import (
44 "math/big"
55 "math/bits"
6-
7- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
86)
97
108const (
@@ -99,27 +97,56 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
9997 return v , nil
10098 }
10199
100+ s , neg , specialValue := setSpecialValue (s , v )
101+ if specialValue != nil {
102+ return specialValue , nil
103+ }
104+ var err error
105+ v , err = parseNumber (s , v , precision , scale , neg )
106+ if err != nil {
107+ return nil , err
108+ }
109+
110+ return v , nil
111+ }
112+
113+ func setSpecialValue (s string , v * big.Int ) (string , bool , * big.Int ) {
114+ s , neg := parseSign (s )
115+
116+ return parseSpecialValue (s , neg , v )
117+ }
118+
119+ func parseSign (s string ) (string , bool ) {
102120 neg := s [0 ] == '-'
103121 if neg || s [0 ] == '+' {
104122 s = s [1 :]
105123 }
124+
125+ return s , neg
126+ }
127+
128+ func parseSpecialValue (s string , neg bool , v * big.Int ) (string , bool , * big.Int ) {
106129 if isInf (s ) {
107130 if neg {
108- return v .Set (neginf ), nil
131+ return s , neg , v .Set (neginf )
109132 }
110133
111- return v .Set (inf ), nil
134+ return s , neg , v .Set (inf )
112135 }
113136 if isNaN (s ) {
114137 if neg {
115- return v .Set (negnan ), nil
138+ return s , neg , v .Set (negnan )
116139 }
117140
118- return v .Set (nan ), nil
141+ return s , neg , v .Set (nan )
119142 }
120143
121- integral := precision - scale
144+ return s , neg , nil
145+ }
122146
147+ func parseNumber (s string , v * big.Int , precision , scale uint32 , neg bool ) (* big.Int , error ) {
148+ var err error
149+ integral := precision - scale
123150 var dot bool
124151 for ; len (s ) > 0 ; s = s [1 :] {
125152 c := s [0 ]
@@ -131,12 +158,10 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
131158
132159 continue
133160 }
134- if dot {
135- if scale > 0 {
136- scale --
137- } else {
138- break
139- }
161+ if dot && scale > 0 {
162+ scale --
163+ } else if dot {
164+ break
140165 }
141166
142167 if ! isDigit (c ) {
@@ -155,30 +180,10 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
155180 }
156181 integral --
157182 }
158- //nolint:nestif
159183 if len (s ) > 0 { // Characters remaining.
160- c := s [0 ]
161- if ! isDigit (c ) {
162- return nil , syntaxError (s )
163- }
164- plus := c > '5'
165- if ! plus && c == '5' {
166- var x big.Int
167- plus = x .And (v , one ).Cmp (zero ) != 0 // Last digit is not a zero.
168- for ! plus && len (s ) > 1 {
169- s = s [1 :]
170- c := s [0 ]
171- if ! isDigit (c ) {
172- return nil , syntaxError (s )
173- }
174- plus = c != '0'
175- }
176- }
177- if plus {
178- v .Add (v , one )
179- if v .Cmp (pow (ten , precision )) >= 0 {
180- v .Set (inf )
181- }
184+ v , err = handleRemainingDigits (s , v , precision )
185+ if err != nil {
186+ return nil , err
182187 }
183188 }
184189 v .Mul (v , pow (ten , scale ))
@@ -189,26 +194,54 @@ func Parse(s string, precision, scale uint32) (*big.Int, error) {
189194 return v , nil
190195}
191196
197+ func handleRemainingDigits (s string , v * big.Int , precision uint32 ) (* big.Int , error ) {
198+ c := s [0 ]
199+ if ! isDigit (c ) {
200+ return nil , syntaxError (s )
201+ }
202+ plus := c > '5'
203+ if ! plus && c == '5' {
204+ var x big.Int
205+ plus = x .And (v , one ).Cmp (zero ) != 0 // Last digit is not a zero.
206+ for ! plus && len (s ) > 1 {
207+ s = s [1 :]
208+ c := s [0 ]
209+ if ! isDigit (c ) {
210+ return nil , syntaxError (s )
211+ }
212+ plus = c != '0'
213+ }
214+ }
215+ if plus {
216+ v .Add (v , one )
217+ if v .Cmp (pow (ten , precision )) >= 0 {
218+ v .Set (inf )
219+ }
220+ }
221+
222+ return v , nil
223+ }
224+
192225// Format returns the string representation of x with the given precision and
193226// scale.
194227func Format (x * big.Int , precision , scale uint32 ) string {
195- switch {
196- case x .CmpAbs (inf ) == 0 :
228+ // Check for special values and nil pointer upfront.
229+ if x == nil {
230+ return "0"
231+ }
232+ if x .CmpAbs (inf ) == 0 {
197233 if x .Sign () < 0 {
198234 return "-inf"
199235 }
200236
201237 return "inf"
202-
203- case x .CmpAbs (nan ) == 0 :
238+ }
239+ if x .CmpAbs (nan ) == 0 {
204240 if x .Sign () < 0 {
205241 return "-nan"
206242 }
207243
208244 return "nan"
209-
210- case x == nil :
211- return "0"
212245 }
213246
214247 v := big .NewInt (0 ).Set (x )
@@ -232,42 +265,59 @@ func Format(x *big.Int, precision, scale uint32) string {
232265
233266 digit .Mod (v , ten )
234267 d := int (digit .Int64 ())
235- if d != 0 || scale == 0 || pos > 0 {
236- const numbers = "0123456789"
237- pos --
238- bts [ pos ] = numbers [ d ]
268+
269+ pos --
270+ if d != 0 || scale == 0 || pos >= 0 {
271+ setDigitAtPosition ( bts , pos , d )
239272 }
273+
240274 if scale > 0 {
241275 scale --
242276 if scale == 0 && pos > 0 {
277+ bts [pos - 1 ] = '.'
243278 pos --
244- bts [pos ] = '.'
245279 }
246280 }
247281 }
248- if scale > 0 {
249- for ; scale > 0 ; scale -- {
250- if precision == 0 {
251- return errorTag
252- }
253- precision --
254- pos --
255- bts [pos ] = '0'
256- }
257282
283+ for ; scale > 0 ; scale -- {
284+ if precision == 0 {
285+ pos = 0
286+
287+ break
288+ }
289+ precision --
258290 pos --
259- bts [pos ] = '. '
291+ bts [pos ] = '0 '
260292 }
293+
261294 if bts [pos ] == '.' {
262295 pos --
263296 bts [pos ] = '0'
264297 }
298+
265299 if neg {
266300 pos --
267301 bts [pos ] = '-'
268302 }
269303
270- return xstring .FromBytes (bts [pos :])
304+ return string (bts [pos :])
305+ }
306+
307+ func abs (x * big.Int ) (* big.Int , bool ) {
308+ v := big .NewInt (0 ).Set (x )
309+ neg := x .Sign () < 0
310+ if neg {
311+ // Convert negative to positive.
312+ v .Neg (x )
313+ }
314+
315+ return v , neg
316+ }
317+
318+ func setDigitAtPosition (bts []byte , pos , digit int ) {
319+ const numbers = "0123456789"
320+ bts [pos ] = numbers [digit ]
271321}
272322
273323// BigIntToByte returns the 16-byte array representation of x.
0 commit comments