| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#define PERL_NO_GET_CONTEXT |
|
2
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
3
|
|
|
|
|
|
|
#include "perl.h" |
|
4
|
|
|
|
|
|
|
#include "XSUB.h" |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
#include |
|
7
|
|
|
|
|
|
|
#include |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 |
|
10
|
|
|
|
|
|
|
#define HAVE_INT128 1 |
|
11
|
|
|
|
|
|
|
typedef unsigned __int128 u128_t; |
|
12
|
|
|
|
|
|
|
#endif |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
#include "decimal.h" |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
const uint64_t pow10_u64[20] = { |
|
17
|
|
|
|
|
|
|
1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, |
|
18
|
|
|
|
|
|
|
1000000ULL, 10000000ULL, 100000000ULL, 1000000000ULL, |
|
19
|
|
|
|
|
|
|
10000000000ULL, 100000000000ULL, 1000000000000ULL, |
|
20
|
|
|
|
|
|
|
10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, |
|
21
|
|
|
|
|
|
|
10000000000000000ULL, 100000000000000000ULL, |
|
22
|
|
|
|
|
|
|
1000000000000000000ULL, 10000000000000000000ULL |
|
23
|
|
|
|
|
|
|
}; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
static const double decimal_pow10_table[] = { |
|
26
|
|
|
|
|
|
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, |
|
27
|
|
|
|
|
|
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, |
|
28
|
|
|
|
|
|
|
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, |
|
29
|
|
|
|
|
|
|
1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38 |
|
30
|
|
|
|
|
|
|
}; |
|
31
|
|
|
|
|
|
|
|
|
32
|
21
|
|
|
|
|
|
double decimal_pow10(int n) { |
|
33
|
21
|
50
|
|
|
|
|
if (n >= 0 && n <= 38) return decimal_pow10_table[n]; |
|
|
|
50
|
|
|
|
|
|
|
34
|
0
|
|
|
|
|
|
return pow(10.0, n); |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
/* Long-double powers of 10 for Decimal128/256 float-path multiplication. |
|
38
|
|
|
|
|
|
|
* Computed at extended precision so the scale doesn't double-round. */ |
|
39
|
6
|
|
|
|
|
|
long double decimal_pow10l(int n) { |
|
40
|
6
|
50
|
|
|
|
|
if (n < 0) return powl(10.0L, n); |
|
41
|
6
|
|
|
|
|
|
long double r = 1.0L; |
|
42
|
|
|
|
|
|
|
int i; |
|
43
|
10
|
100
|
|
|
|
|
for (i = 0; i < n; i++) r *= 10.0L; |
|
44
|
6
|
|
|
|
|
|
return r; |
|
45
|
|
|
|
|
|
|
} |
|
46
|
|
|
|
|
|
|
|
|
47
|
7653
|
|
|
|
|
|
static int mul10_128(uint64_t *hi, uint64_t *lo) { |
|
48
|
|
|
|
|
|
|
#ifdef HAVE_INT128 |
|
49
|
7653
|
|
|
|
|
|
u128_t prod_lo = (u128_t)*lo * 10; |
|
50
|
7653
|
|
|
|
|
|
u128_t prod_hi = (u128_t)*hi * 10 + (uint64_t)(prod_lo >> 64); |
|
51
|
7653
|
|
|
|
|
|
*lo = (uint64_t)prod_lo; |
|
52
|
7653
|
|
|
|
|
|
*hi = (uint64_t)prod_hi; |
|
53
|
7653
|
|
|
|
|
|
return (prod_hi >> 64) == 0; |
|
54
|
|
|
|
|
|
|
#else |
|
55
|
|
|
|
|
|
|
/* 32-bit limb fallback. */ |
|
56
|
|
|
|
|
|
|
uint64_t lo_lo = *lo & 0xFFFFFFFFULL; |
|
57
|
|
|
|
|
|
|
uint64_t lo_hi = *lo >> 32; |
|
58
|
|
|
|
|
|
|
uint64_t p_lo = lo_lo * 10; |
|
59
|
|
|
|
|
|
|
uint64_t p_hi = lo_hi * 10 + (p_lo >> 32); |
|
60
|
|
|
|
|
|
|
uint64_t carry = p_hi >> 32; |
|
61
|
|
|
|
|
|
|
*lo = (p_hi << 32) | (p_lo & 0xFFFFFFFFULL); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
uint64_t hi_lo = *hi & 0xFFFFFFFFULL; |
|
64
|
|
|
|
|
|
|
uint64_t hi_hi = *hi >> 32; |
|
65
|
|
|
|
|
|
|
uint64_t q_lo = hi_lo * 10 + (carry & 0xFFFFFFFFULL); |
|
66
|
|
|
|
|
|
|
uint64_t q_hi = hi_hi * 10 + (q_lo >> 32) + (carry >> 32); |
|
67
|
|
|
|
|
|
|
*hi = (q_hi << 32) | (q_lo & 0xFFFFFFFFULL); |
|
68
|
|
|
|
|
|
|
return (q_hi >> 32) == 0; |
|
69
|
|
|
|
|
|
|
#endif |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
571
|
|
|
|
|
|
static int mul10_256(uint64_t limbs[4]) { |
|
73
|
571
|
|
|
|
|
|
uint64_t carry = 0; |
|
74
|
|
|
|
|
|
|
int i; |
|
75
|
2855
|
100
|
|
|
|
|
for (i = 0; i < 4; i++) { |
|
76
|
|
|
|
|
|
|
#ifdef HAVE_INT128 |
|
77
|
2284
|
|
|
|
|
|
u128_t prod = (u128_t)limbs[i] * 10 + carry; |
|
78
|
2284
|
|
|
|
|
|
limbs[i] = (uint64_t)prod; |
|
79
|
2284
|
|
|
|
|
|
carry = (uint64_t)(prod >> 64); |
|
80
|
|
|
|
|
|
|
#else |
|
81
|
|
|
|
|
|
|
uint64_t lo_lo = limbs[i] & 0xFFFFFFFFULL; |
|
82
|
|
|
|
|
|
|
uint64_t lo_hi = limbs[i] >> 32; |
|
83
|
|
|
|
|
|
|
uint64_t p_lo = lo_lo * 10 + (carry & 0xFFFFFFFFULL); |
|
84
|
|
|
|
|
|
|
uint64_t p_hi = lo_hi * 10 + (p_lo >> 32) + (carry >> 32); |
|
85
|
|
|
|
|
|
|
limbs[i] = (p_hi << 32) | (p_lo & 0xFFFFFFFFULL); |
|
86
|
|
|
|
|
|
|
carry = p_hi >> 32; |
|
87
|
|
|
|
|
|
|
#endif |
|
88
|
|
|
|
|
|
|
} |
|
89
|
571
|
|
|
|
|
|
return carry == 0; |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
575
|
|
|
|
|
|
int add_digit_256(uint64_t limbs[4], uint64_t digit) { |
|
93
|
575
|
|
|
|
|
|
uint64_t carry = digit; |
|
94
|
|
|
|
|
|
|
int i; |
|
95
|
1110
|
100
|
|
|
|
|
for (i = 0; i < 4 && carry; i++) { |
|
|
|
100
|
|
|
|
|
|
|
96
|
535
|
|
|
|
|
|
uint64_t old = limbs[i]; |
|
97
|
535
|
|
|
|
|
|
limbs[i] = old + carry; |
|
98
|
535
|
|
|
|
|
|
carry = (limbs[i] < old) ? 1 : 0; |
|
99
|
|
|
|
|
|
|
} |
|
100
|
575
|
|
|
|
|
|
return (int)carry; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
2033
|
|
|
|
|
|
int parse_decimal128_str(const char *s, STRLEN len, int scale, |
|
104
|
|
|
|
|
|
|
uint64_t *hi_out, uint64_t *lo_out) { |
|
105
|
2033
|
|
|
|
|
|
STRLEN i = 0; |
|
106
|
2033
|
|
|
|
|
|
int neg = 0, seen_digit = 0, seen_dot = 0, frac_used = 0; |
|
107
|
2033
|
|
|
|
|
|
uint64_t lo = 0, hi = 0; |
|
108
|
|
|
|
|
|
|
|
|
109
|
2033
|
50
|
|
|
|
|
while (i < len && (s[i] == ' ' || s[i] == '\t')) i++; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
110
|
2033
|
50
|
|
|
|
|
if (i < len && (s[i] == '+' || s[i] == '-')) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
111
|
10
|
50
|
|
|
|
|
if (s[i] == '-') neg = 1; |
|
112
|
10
|
|
|
|
|
|
i++; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
8700
|
100
|
|
|
|
|
while (i < len) { |
|
116
|
6668
|
|
|
|
|
|
char c = s[i++]; |
|
117
|
6668
|
100
|
|
|
|
|
if (c == '.') { |
|
118
|
1016
|
50
|
|
|
|
|
if (seen_dot) return 0; |
|
119
|
1016
|
|
|
|
|
|
seen_dot = 1; |
|
120
|
1016
|
|
|
|
|
|
continue; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
5652
|
50
|
|
|
|
|
if (c < '0' || c > '9') return 0; |
|
|
|
50
|
|
|
|
|
|
|
123
|
5652
|
|
|
|
|
|
seen_digit = 1; |
|
124
|
5652
|
100
|
|
|
|
|
if (seen_dot) { |
|
125
|
2076
|
50
|
|
|
|
|
if (frac_used >= scale) continue; /* truncate */ |
|
126
|
2076
|
|
|
|
|
|
frac_used++; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
5652
|
50
|
|
|
|
|
if (!mul10_128(&hi, &lo)) return 0; |
|
129
|
5652
|
|
|
|
|
|
uint64_t digit = (uint64_t)(c - '0'); |
|
130
|
|
|
|
|
|
|
/* (hi:lo) + digit overflows iff hi == UINT64_MAX and lo wraps. */ |
|
131
|
5652
|
100
|
|
|
|
|
if (hi == 0xFFFFFFFFFFFFFFFFULL && lo > 0xFFFFFFFFFFFFFFFFULL - digit) |
|
|
|
100
|
|
|
|
|
|
|
132
|
1
|
|
|
|
|
|
return 0; |
|
133
|
5651
|
|
|
|
|
|
uint64_t newlo = lo + digit; |
|
134
|
5651
|
100
|
|
|
|
|
if (newlo < lo) hi++; |
|
135
|
5651
|
|
|
|
|
|
lo = newlo; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
2032
|
50
|
|
|
|
|
if (!seen_digit) return 0; |
|
139
|
|
|
|
|
|
|
|
|
140
|
4033
|
100
|
|
|
|
|
while (frac_used < scale) { |
|
141
|
2001
|
50
|
|
|
|
|
if (!mul10_128(&hi, &lo)) return 0; |
|
142
|
2001
|
|
|
|
|
|
frac_used++; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
/* Reject magnitudes that don't fit signed 128-bit (Decimal128 storage). |
|
146
|
|
|
|
|
|
|
* The asymmetric extreme -2^127 has hi=0x80..., lo=0 with neg=1; allow it. */ |
|
147
|
2032
|
100
|
|
|
|
|
if (hi > 0x8000000000000000ULL) return 0; |
|
148
|
2031
|
100
|
|
|
|
|
if (hi == 0x8000000000000000ULL && (!neg || lo != 0)) return 0; |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
|
150
|
2029
|
100
|
|
|
|
|
if (neg) { |
|
151
|
10
|
|
|
|
|
|
lo = ~lo + 1; |
|
152
|
10
|
100
|
|
|
|
|
hi = ~hi + (lo == 0 ? 1 : 0); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
2029
|
|
|
|
|
|
*lo_out = lo; |
|
156
|
2029
|
|
|
|
|
|
*hi_out = hi; |
|
157
|
2029
|
|
|
|
|
|
return 1; |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
13
|
|
|
|
|
|
int parse_decimal256_str(const char *s, STRLEN len, int scale, |
|
161
|
|
|
|
|
|
|
uint64_t limbs_out[4]) { |
|
162
|
13
|
|
|
|
|
|
STRLEN i = 0; |
|
163
|
13
|
|
|
|
|
|
int neg = 0, seen_digit = 0, seen_dot = 0, frac_used = 0; |
|
164
|
13
|
|
|
|
|
|
uint64_t limbs[4] = {0,0,0,0}; |
|
165
|
|
|
|
|
|
|
|
|
166
|
13
|
50
|
|
|
|
|
while (i < len && (s[i] == ' ' || s[i] == '\t')) i++; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
167
|
13
|
50
|
|
|
|
|
if (i < len && (s[i] == '+' || s[i] == '-')) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
168
|
4
|
50
|
|
|
|
|
if (s[i] == '-') neg = 1; |
|
169
|
4
|
|
|
|
|
|
i++; |
|
170
|
|
|
|
|
|
|
} |
|
171
|
589
|
100
|
|
|
|
|
while (i < len) { |
|
172
|
577
|
|
|
|
|
|
char c = s[i++]; |
|
173
|
577
|
100
|
|
|
|
|
if (c == '.') { |
|
174
|
6
|
50
|
|
|
|
|
if (seen_dot) return 0; |
|
175
|
6
|
|
|
|
|
|
seen_dot = 1; |
|
176
|
6
|
|
|
|
|
|
continue; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
571
|
50
|
|
|
|
|
if (c < '0' || c > '9') return 0; |
|
|
|
50
|
|
|
|
|
|
|
179
|
571
|
|
|
|
|
|
seen_digit = 1; |
|
180
|
571
|
100
|
|
|
|
|
if (seen_dot) { |
|
181
|
16
|
50
|
|
|
|
|
if (frac_used >= scale) continue; |
|
182
|
16
|
|
|
|
|
|
frac_used++; |
|
183
|
|
|
|
|
|
|
} |
|
184
|
571
|
50
|
|
|
|
|
if (!mul10_256(limbs)) return 0; |
|
185
|
571
|
100
|
|
|
|
|
if (add_digit_256(limbs, (uint64_t)(c - '0'))) return 0; |
|
186
|
|
|
|
|
|
|
} |
|
187
|
12
|
50
|
|
|
|
|
if (!seen_digit) return 0; |
|
188
|
12
|
50
|
|
|
|
|
while (frac_used < scale) { |
|
189
|
0
|
0
|
|
|
|
|
if (!mul10_256(limbs)) return 0; |
|
190
|
0
|
|
|
|
|
|
frac_used++; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
/* Reject magnitudes that don't fit signed 256-bit. Allow only the |
|
193
|
|
|
|
|
|
|
* asymmetric extreme -2^255 (top bit set, rest zero, negative). */ |
|
194
|
12
|
50
|
|
|
|
|
if (limbs[3] > 0x8000000000000000ULL) return 0; |
|
195
|
12
|
100
|
|
|
|
|
if (limbs[3] == 0x8000000000000000ULL |
|
196
|
2
|
100
|
|
|
|
|
&& (!neg || limbs[0] != 0 || limbs[1] != 0 || limbs[2] != 0)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
197
|
1
|
|
|
|
|
|
return 0; |
|
198
|
11
|
100
|
|
|
|
|
if (neg) { |
|
199
|
|
|
|
|
|
|
int j; |
|
200
|
20
|
100
|
|
|
|
|
for (j = 0; j < 4; j++) limbs[j] = ~limbs[j]; |
|
201
|
4
|
|
|
|
|
|
add_digit_256(limbs, 1); |
|
202
|
|
|
|
|
|
|
} |
|
203
|
11
|
|
|
|
|
|
limbs_out[0] = limbs[0]; |
|
204
|
11
|
|
|
|
|
|
limbs_out[1] = limbs[1]; |
|
205
|
11
|
|
|
|
|
|
limbs_out[2] = limbs[2]; |
|
206
|
11
|
|
|
|
|
|
limbs_out[3] = limbs[3]; |
|
207
|
11
|
|
|
|
|
|
return 1; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
2013
|
|
|
|
|
|
int parse_decimal_int64_str(const char *s, STRLEN len, int scale, |
|
211
|
|
|
|
|
|
|
int64_t *out) { |
|
212
|
|
|
|
|
|
|
uint64_t lo, hi; |
|
213
|
2013
|
50
|
|
|
|
|
if (!parse_decimal128_str(s, len, scale, &hi, &lo)) return 0; |
|
214
|
|
|
|
|
|
|
/* Fits in int64 iff hi is sign extension of lo's high bit. */ |
|
215
|
2013
|
100
|
|
|
|
|
if (hi == 0 && (lo & 0x8000000000000000ULL) == 0) { |
|
|
|
50
|
|
|
|
|
|
|
216
|
2010
|
|
|
|
|
|
*out = (int64_t)lo; |
|
217
|
2010
|
|
|
|
|
|
return 1; |
|
218
|
|
|
|
|
|
|
} |
|
219
|
3
|
50
|
|
|
|
|
if (hi == ~(uint64_t)0 && (lo & 0x8000000000000000ULL)) { |
|
|
|
50
|
|
|
|
|
|
|
220
|
3
|
|
|
|
|
|
*out = (int64_t)lo; |
|
221
|
3
|
|
|
|
|
|
return 1; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
0
|
|
|
|
|
|
return 0; |
|
224
|
|
|
|
|
|
|
} |