@@ -50,39 +50,78 @@ struct BigDecimal < Number
50
50
51
51
raise InvalidBigDecimalException .new(str, " Zero size" ) if str.bytesize == 0
52
52
53
- # Check str's validity and find index of .
53
+ # Check str's validity and find index of '.'
54
54
decimal_index = nil
55
+ # Check str's validity and find index of 'e'
56
+ exponent_index = nil
57
+
55
58
str.each_char_with_index do |char , index |
56
59
case char
57
60
when '-'
58
- if index != 0
61
+ unless index == 0 || exponent_index == index - 1
59
62
raise InvalidBigDecimalException .new(str, " Unexpected '-' character" )
60
63
end
64
+ when '+'
65
+ unless exponent_index == index - 1
66
+ raise InvalidBigDecimalException .new(str, " Unexpected '+' character" )
67
+ end
61
68
when '.'
62
69
if decimal_index
63
70
raise InvalidBigDecimalException .new(str, " Unexpected '.' character" )
64
71
end
65
-
66
72
decimal_index = index
73
+ when 'e' , 'E'
74
+ if exponent_index
75
+ raise InvalidBigDecimalException .new(str, " Unexpected #{ char.inspect } character" )
76
+ end
77
+ exponent_index = index
67
78
when '0' ..'9'
68
79
# Pass
69
80
else
70
81
raise InvalidBigDecimalException .new(str, " Unexpected #{ char.inspect } character" )
71
82
end
72
83
end
73
84
85
+ decimal_end_index = (exponent_index || str.bytesize) - 1
74
86
if decimal_index
87
+ decimal_count = (decimal_end_index - decimal_index).to_u64
88
+
75
89
value_str = String .build do |builder |
76
90
# We know this is ASCII, so we can slice by index
77
91
builder.write(str.to_slice[0 , decimal_index])
78
- builder.write(str.to_slice[decimal_index + 1 , str.bytesize - decimal_index - 1 ])
92
+ builder.write(str.to_slice[decimal_index + 1 , decimal_count ])
79
93
end
80
-
81
94
@value = value_str.to_big_i
82
- @scale = (str.bytesize - decimal_index - 1 ).to_u64
83
95
else
84
- @value = str.to_big_i
85
- @scale = 0 _u64
96
+ decimal_count = 0 _u64
97
+ @value = str[0 ..decimal_end_index].to_big_i
98
+ end
99
+
100
+ if exponent_index
101
+ exponent_postfix = str[exponent_index + 1 ]
102
+ case exponent_postfix
103
+ when '+' , '-'
104
+ exponent_positive = exponent_postfix == '+'
105
+ exponent = str[(exponent_index + 2 )..- 1 ].to_u64
106
+ else
107
+ exponent_positive = true
108
+ exponent = str[(exponent_index + 1 )..- 1 ].to_u64
109
+ end
110
+
111
+ @scale = exponent
112
+ if exponent_positive
113
+ if @scale < decimal_count
114
+ @scale = decimal_count - @scale
115
+ else
116
+ @scale -= decimal_count
117
+ @value *= 10 .to_big_i ** @scale
118
+ @scale = 0 _u64
119
+ end
120
+ else
121
+ @scale += decimal_count
122
+ end
123
+ else
124
+ @scale = decimal_count
86
125
end
87
126
end
88
127
0 commit comments