1use std::cmp::Ordering;
4
5use rupg_common::SqlState;
6
7use super::{
8 DEC_DIGITS, MIN_SIG_DIGITS, NBASE, Numeric, NumericSign, Var, overflow, select_div_scale,
9};
10use crate::error::TypeError;
11use crate::prng::Prng;
12
13const NBASE_SQR: i64 = 100_000_000;
15const MUL_GUARD_DIGITS: i64 = 2;
17const DIV_GUARD_DIGITS: i64 = 4;
19const MAX_DISPLAY_SCALE: i64 = 1000;
21const WEIGHT_MAX: i64 = i16::MAX as i64;
23const EXP_LIMIT: f64 = 6000.0;
25#[allow(clippy::approx_constant)]
28const LOG10_E: f64 = 0.434294481903252;
29#[allow(clippy::approx_constant)]
31const LOG10_2: f64 = 0.301029995663981;
32#[allow(clippy::approx_constant)]
34const LN_10: f64 = 2.302585092994046;
35
36fn log_error(message: &str) -> TypeError {
37 TypeError::new(SqlState::INVALID_ARGUMENT_FOR_LOG, message.to_string())
38}
39
40fn power_error(message: &str) -> TypeError {
41 TypeError::new(SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION, message.to_string())
42}
43
44fn division_by_zero() -> TypeError {
45 TypeError::new(SqlState::DIVISION_BY_ZERO, "division by zero".to_string())
46}
47
48fn result_scale(dweight: i64, scales: &[i64]) -> i64 {
50 let rscale = scales.iter().fold(MIN_SIG_DIGITS - dweight, |r, &s| r.max(s));
51 rscale.clamp(0, MAX_DISPLAY_SCALE)
52}
53
54impl Var {
55 fn zero(dscale: i64) -> Var {
56 Var { sign: NumericSign::Positive, weight: 0, dscale, digits: Vec::new() }
57 }
58
59 fn int(value: i64) -> Var {
61 let sign = if value < 0 { NumericSign::Negative } else { NumericSign::Positive };
62 let mut rest = value.unsigned_abs();
63 let mut digits = Vec::new();
64 while rest > 0 {
65 digits.insert(0, (rest % NBASE as u64) as i32);
66 rest /= NBASE as u64;
67 }
68 let weight = digits.len() as i64 - 1;
69 let mut var = Var { sign, weight, dscale: 0, digits };
70 var.strip();
71 var
72 }
73
74 fn point_nine() -> Var {
76 Var { sign: NumericSign::Positive, weight: -1, dscale: 1, digits: vec![9000] }
77 }
78
79 fn one_point_one() -> Var {
81 Var { sign: NumericSign::Positive, weight: 0, dscale: 1, digits: vec![1, 1000] }
82 }
83
84 fn is_zero(&self) -> bool {
85 self.digits.is_empty()
86 }
87
88 fn cmp(&self, other: &Var) -> Ordering {
90 let negative = |v: &Var| !v.is_zero() && v.sign == NumericSign::Negative;
91 let positive = |v: &Var| !v.is_zero() && v.sign == NumericSign::Positive;
92 match (negative(self), negative(other)) {
93 (true, false) => Ordering::Less,
94 (false, true) => Ordering::Greater,
95 (true, true) => other.cmp_abs(self),
96 (false, false) if positive(self) || positive(other) => self.cmp_abs(other),
97 (false, false) => Ordering::Equal,
98 }
99 }
100
101 fn sub(&self, other: &Var) -> Var {
103 let mut negated = other.clone();
104 negated.sign = match other.sign {
105 NumericSign::Positive if !other.is_zero() => NumericSign::Negative,
106 _ => NumericSign::Positive,
107 };
108 self.add(&negated)
109 }
110
111 fn to_f64(&self) -> f64 {
113 let mut text = String::new();
114 if self.sign == NumericSign::Negative {
115 text.push('-');
116 }
117 if self.weight < 0 {
118 text.push('0');
119 } else {
120 text.push_str(&self.digit(self.weight).to_string());
121 for w in (0..self.weight).rev() {
122 text.push_str(&format!("{:04}", self.digit(w)));
123 }
124 }
125 if self.dscale > 0 {
126 text.push('.');
127 let end = text.len() + self.dscale as usize;
128 let mut w = -1;
129 while text.len() < end {
130 text.push_str(&format!("{:04}", self.digit(w)));
131 w -= 1;
132 }
133 text.truncate(end);
134 }
135 text.parse().unwrap_or(f64::NAN)
136 }
137
138 fn to_i64(&self) -> Option<i64> {
140 let mut value: i64 = 0;
141 for w in (0..=self.weight).rev() {
142 value = value.checked_mul(i64::from(NBASE))?.checked_add(i64::from(self.digit(w)))?;
143 }
144 Some(if self.sign == NumericSign::Negative { -value } else { value })
145 }
146
147 fn pair(&self, i: usize) -> i64 {
149 let high = i64::from(self.digits[2 * i]) * i64::from(NBASE);
150 high + self.digits.get(2 * i + 1).map_or(0, |&d| i64::from(d))
151 }
152
153 fn mul_round(&self, other: &Var, rscale: i64) -> Var {
155 let (a, b) =
156 if self.digits.len() > other.digits.len() { (other, self) } else { (self, other) };
157 if a.is_zero() {
158 return Var::zero(rscale);
159 }
160 if a.digits.len() <= 6 && rscale == a.dscale + b.dscale {
161 let mut product = a.mul(b);
163 product.dscale = rscale;
164 return product;
165 }
166 let sign = if a.sign == b.sign { NumericSign::Positive } else { NumericSign::Negative };
167 let (n1, n2) = (a.digits.len() as i64, b.digits.len() as i64);
168 let (mut pairs1, mut pairs2) = ((n1 + 1) / 2, (n2 + 1) / 2);
169 let res_ndigits = n1 + n2;
170 let mut res_pairs = res_ndigits / 2 + 1;
171 let pair_offset = res_pairs - pairs1 - pairs2 + 1;
172 let res_weight =
173 a.weight + b.weight + 1 + 2 * res_pairs - res_ndigits - (n1 & 1) - (n2 & 1);
174 let maxdigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS + MUL_GUARD_DIGITS;
175 res_pairs = res_pairs.min(maxdigits / 2 + 1);
176 if res_pairs <= pair_offset {
177 return Var::zero(rscale);
178 }
179 pairs1 = pairs1.min(res_pairs - pair_offset);
180 pairs2 = pairs2.min(res_pairs - pair_offset);
181 let right: Vec<u128> = (0..pairs2 as usize).map(|i| b.pair(i) as u128).collect();
182 let mut dig = vec![0u128; res_pairs as usize];
183 for i1 in 0..pairs1 {
184 let left = a.pair(i1 as usize) as u128;
185 if left == 0 {
186 continue;
187 }
188 let limit = pairs2.min(res_pairs - i1 - pair_offset);
189 let at = (i1 + pair_offset) as usize;
190 for (slot, &r) in dig[at..].iter_mut().zip(&right[..limit as usize]) {
191 *slot += left * r;
192 }
193 }
194 let mut digits = vec![0; 2 * res_pairs as usize];
195 let mut carry = 0u128;
196 for (i, &d) in dig.iter().enumerate().rev() {
197 let total = d + carry;
198 let low = (total % NBASE_SQR as u128) as i64;
199 carry = total / NBASE_SQR as u128;
200 digits[2 * i] = (low / i64::from(NBASE)) as i32;
201 digits[2 * i + 1] = (low % i64::from(NBASE)) as i32;
202 }
203 let mut product = Var { sign, weight: res_weight, dscale: 0, digits };
204 product.round(rscale);
205 product.strip();
206 product
207 }
208
209 fn div_round(
211 &self,
212 other: &Var,
213 rscale: i64,
214 round: bool,
215 exact: bool,
216 ) -> Result<Var, TypeError> {
217 if other.is_zero() || other.digits[0] == 0 {
218 return Err(division_by_zero());
219 }
220 if self.is_zero() {
221 return Ok(Var::zero(rscale));
222 }
223 if exact || other.digits.len() as i64 <= 2 * (DIV_GUARD_DIGITS + 2) {
224 return Ok(self.div(other, rscale, round));
225 }
226 Ok(self.div_estimate(other, rscale, round))
227 }
228
229 fn div_estimate(&self, other: &Var, rscale: i64, round: bool) -> Var {
231 let sign =
232 if self.sign == other.sign { NumericSign::Positive } else { NumericSign::Negative };
233 let res_weight = self.weight - other.weight + 1;
234 let mut res_ndigits = (res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS).max(1);
235 if round {
236 res_ndigits += 1;
237 }
238 res_ndigits += DIV_GUARD_DIGITS;
239 let res_pairs = ((res_ndigits + 1) / 2) as usize;
240 let div_pairs = res_pairs;
241 let pairs1 = self.digits.len().div_ceil(2).min(div_pairs);
242 let pairs2 = other.digits.len().div_ceil(2).min(div_pairs);
243 let mut dividend = vec![0i64; div_pairs + 1];
244 for (i, slot) in dividend.iter_mut().enumerate().take(pairs1) {
245 *slot = self.pair(i);
246 }
247 let divisor: Vec<i64> = (0..pairs2).map(|i| other.pair(i)).collect();
248 let mut fdivisor = divisor[0] as f64 * NBASE_SQR as f64;
249 if pairs2 > 1 {
250 fdivisor += divisor[1] as f64;
251 }
252 let inverse = 1.0 / fdivisor;
253 let estimate = |dividend: &[i64], qi: usize| -> i32 {
254 let fdividend = dividend[qi] as f64 * NBASE_SQR as f64 + dividend[qi + 1] as f64;
255 let quotient = fdividend * inverse;
256 if quotient >= 0.0 { quotient as i32 } else { quotient as i32 - 1 }
257 };
258 let limit = (i64::MAX - i64::MAX / NBASE_SQR - 1) / (NBASE_SQR - 1);
259 let mut maxdiv: i64 = 1;
260 for qi in 0..res_pairs {
261 let mut qdigit = estimate(÷nd, qi);
262 if qdigit != 0 {
263 maxdiv += i64::from(qdigit).abs();
264 if maxdiv > limit {
265 let mut carry = 0;
267 let mut i = (qi + pairs2 - 2).min(div_pairs - 1);
268 while i > qi {
269 let total = dividend[i] + carry;
270 carry = total.div_euclid(NBASE_SQR);
271 dividend[i] = total.rem_euclid(NBASE_SQR);
272 i -= 1;
273 }
274 dividend[qi] += carry;
275 maxdiv = 1;
276 qdigit = estimate(÷nd, qi);
277 maxdiv += i64::from(qdigit).abs();
278 }
279 if qdigit != 0 {
280 let stop = pairs2.min(div_pairs - qi);
281 for (slot, &d) in dividend[qi..qi + stop].iter_mut().zip(&divisor) {
282 *slot -= i64::from(qdigit) * d;
283 }
284 }
285 }
286 dividend[qi + 1] = dividend[qi + 1].wrapping_add(dividend[qi].wrapping_mul(NBASE_SQR));
288 dividend[qi] = i64::from(qdigit);
289 }
290 let mut digits = vec![0; 2 * res_pairs];
291 let mut carry = 0;
292 for i in (0..res_pairs).rev() {
293 let total = dividend[i] + carry;
294 carry = total.div_euclid(NBASE_SQR);
295 let low = total.rem_euclid(NBASE_SQR);
296 digits[2 * i] = (low / i64::from(NBASE)) as i32;
297 digits[2 * i + 1] = (low % i64::from(NBASE)) as i32;
298 }
299 let mut quotient = Var { sign, weight: res_weight, dscale: 0, digits };
300 if round {
301 quotient.round(rscale);
302 } else {
303 quotient.trunc(rscale);
304 }
305 quotient.strip();
306 quotient
307 }
308
309 fn div_int(&self, divisor: i64, rscale: i64) -> Var {
311 self.div(&Var::int(divisor), rscale, true)
312 }
313
314 fn sqrt(&self, rscale: i64) -> Var {
316 if self.is_zero() {
317 return Var::zero(rscale);
318 }
319 let res_weight = self.weight.div_euclid(2);
320 let res_ndigits = if rscale + 1 >= 0 {
321 res_weight + 1 + (rscale + DEC_DIGITS) / DEC_DIGITS
322 } else {
323 res_weight + 1 - (-rscale - 1) / DEC_DIGITS
324 }
325 .max(1);
326 let src_ndigits = (self.weight + 1 + (res_ndigits - res_weight - 1) * 2).max(1);
327 let digits: Vec<i32> =
328 (0..src_ndigits as usize).map(|i| self.digits.get(i).copied().unwrap_or(0)).collect();
329 let mut source =
330 Var { sign: NumericSign::Positive, weight: src_ndigits - 1, dscale: 0, digits };
331 source.strip();
332 let mut root = isqrt(&source);
333 root.weight = res_weight;
334 root.round(rscale);
335 root.strip();
336 root
337 }
338
339 fn exp(&self, rscale: i64) -> Result<Var, TypeError> {
341 let mut x = self.clone();
342 let mut val = x.to_f64();
343 if val.abs() >= EXP_LIMIT {
344 if val > 0.0 {
345 return Err(overflow());
346 }
347 return Ok(Var::zero(rscale));
348 }
349 let dweight = (val * LOG10_E) as i64;
350 let mut ndiv2 = 0;
352 if val.abs() > 0.01 {
353 ndiv2 = 1;
354 val /= 2.0;
355 while val.abs() > 0.01 {
356 ndiv2 += 1;
357 val /= 2.0;
358 }
359 let local_rscale = x.dscale + ndiv2;
360 x = x.div_int(1 << ndiv2, local_rscale);
361 }
362 let sig_digits = (1 + dweight + rscale + (ndiv2 as f64 * LOG10_2) as i64).max(0) + 8;
363 let local_rscale = sig_digits - 1;
364 let mut result = Var::int(1).add(&x);
365 let mut elem = x.mul_round(&x, local_rscale);
366 let mut ni = 2;
367 elem = elem.div_int(ni, local_rscale);
368 while !elem.is_zero() {
369 result = result.add(&elem);
370 elem = elem.mul_round(&x, local_rscale);
371 ni += 1;
372 elem = elem.div_int(ni, local_rscale);
373 }
374 for _ in 0..ndiv2 {
375 let local_rscale = (sig_digits - result.weight * 2 * DEC_DIGITS).max(0);
376 result = result.mul_round(&result, local_rscale);
377 }
378 result.round(rscale);
379 Ok(result)
380 }
381
382 fn estimate_ln_dweight(&self) -> i64 {
384 if self.sign != NumericSign::Positive {
385 return 0;
386 }
387 if self.cmp(&Var::point_nine()) != Ordering::Less
388 && self.cmp(&Var::one_point_one()) != Ordering::Greater
389 {
390 let x = self.sub(&Var::int(1));
392 return match x.digits.first() {
393 Some(&first) => x.weight * DEC_DIGITS + f64::from(first).log10() as i64,
394 None => 0,
395 };
396 }
397 let Some(&first) = self.digits.first() else { return 0 };
398 let mut digits = first;
399 let mut dweight = self.weight * DEC_DIGITS;
400 if let Some(&second) = self.digits.get(1) {
401 digits = digits * NBASE + second;
402 dweight -= DEC_DIGITS;
403 }
404 let ln = f64::from(digits).ln() + dweight as f64 * LN_10;
405 ln.abs().log10() as i64
406 }
407
408 fn ln(&self, rscale: i64) -> Result<Var, TypeError> {
410 match self.cmp(&Var::zero(0)) {
411 Ordering::Equal => return Err(log_error("cannot take logarithm of zero")),
412 Ordering::Less => return Err(log_error("cannot take logarithm of a negative number")),
413 Ordering::Greater => {}
414 }
415 let two = Var::int(2);
416 let mut x = self.clone();
417 let mut fact = two.clone();
418 let mut nsqrt = 0;
419 while x.cmp(&Var::point_nine()) != Ordering::Greater {
421 x = x.sqrt(rscale - x.weight * DEC_DIGITS / 2 + 8);
422 fact = fact.mul_round(&two, 0);
423 nsqrt += 1;
424 }
425 while x.cmp(&Var::one_point_one()) != Ordering::Less {
426 x = x.sqrt(rscale - x.weight * DEC_DIGITS / 2 + 8);
427 fact = fact.mul_round(&two, 0);
428 nsqrt += 1;
429 }
430 let local_rscale = rscale + ((nsqrt + 1) as f64 * LOG10_2) as i64 + 8;
432 let one = Var::int(1);
433 let mut result = x.sub(&one).div_round(&x.add(&one), local_rscale, true, false)?;
434 let mut xx = result.clone();
435 let x = result.mul_round(&result, local_rscale);
436 let mut ni = 1;
437 loop {
438 ni += 2;
439 xx = xx.mul_round(&x, local_rscale);
440 let elem = xx.div_int(ni, local_rscale);
441 if elem.is_zero() {
442 break;
443 }
444 result = result.add(&elem);
445 if elem.weight < result.weight - local_rscale * 2 / DEC_DIGITS {
446 break;
447 }
448 }
449 Ok(result.mul_round(&fact, rscale))
450 }
451
452 fn log(&self, num: &Var) -> Result<Var, TypeError> {
454 let ln_base_dweight = self.estimate_ln_dweight();
455 let ln_num_dweight = num.estimate_ln_dweight();
456 let result_dweight = ln_num_dweight - ln_base_dweight;
457 let rscale = result_scale(result_dweight, &[self.dscale, num.dscale]);
458 let ln_base_rscale = (rscale + result_dweight - ln_base_dweight + 8).max(0);
459 let ln_num_rscale = (rscale + result_dweight - ln_num_dweight + 8).max(0);
460 let ln_base = self.ln(ln_base_rscale)?;
461 let ln_num = num.ln(ln_num_rscale)?;
462 ln_num.div_round(&ln_base, rscale, true, false)
463 }
464
465 fn is_integral(&self) -> bool {
467 self.digits.len() as i64 <= self.weight + 1
468 }
469
470 fn power(&self, exp: &Var) -> Result<Var, TypeError> {
472 if exp.is_integral()
473 && let Some(value) = exp.to_i64()
474 && let Ok(value) = i32::try_from(value)
475 {
476 return self.power_int(value, exp.dscale);
477 }
478 if self.is_zero() {
479 return Ok(Var::zero(MIN_SIG_DIGITS));
480 }
481 let mut base = self.clone();
482 let mut negative = false;
483 if self.sign == NumericSign::Negative {
484 if !exp.is_integral() {
485 return Err(power_error(
486 "a negative number raised to a non-integer power yields a complex result",
487 ));
488 }
489 negative = exp.digits.len() as i64 == exp.weight + 1
490 && exp.digits.last().is_some_and(|d| d & 1 == 1);
491 base.sign = NumericSign::Positive;
492 }
493 let ln_dweight = base.estimate_ln_dweight();
495 let local_rscale = (8 - ln_dweight).max(0);
496 let ln_base = base.ln(local_rscale)?;
497 let ln_num = ln_base.mul_round(exp, local_rscale);
498 let mut val = ln_num.to_f64();
499 if val.abs() > 2000.0 * 3.01 {
500 if val > 0.0 {
501 return Err(overflow());
502 }
503 return Ok(Var::zero(MAX_DISPLAY_SCALE));
504 }
505 val *= LOG10_E;
506 let rscale = result_scale(val as i64, &[base.dscale, exp.dscale]);
507 let sig_digits = (rscale + val as i64).max(0);
508 let local_rscale = (sig_digits - ln_dweight + 8).max(0);
509 let ln_base = base.ln(local_rscale)?;
510 let ln_num = ln_base.mul_round(exp, local_rscale);
511 let mut result = ln_num.exp(rscale)?;
512 if negative && !result.is_zero() {
513 result.sign = NumericSign::Negative;
514 }
515 Ok(result)
516 }
517
518 fn power_int(&self, exp: i32, exp_dscale: i64) -> Result<Var, TypeError> {
520 let f = match self.digits.first() {
522 Some(&first) => {
523 let mut f = f64::from(first);
524 let mut p = self.weight * DEC_DIGITS;
525 for &d in self.digits.iter().skip(1).take(3) {
526 f = f * f64::from(NBASE) + f64::from(d);
527 p -= DEC_DIGITS;
528 }
529 f64::from(exp) * (f.log10() + p as f64)
530 }
531 None => 0.0,
532 };
533 if f > ((WEIGHT_MAX + 1) * DEC_DIGITS) as f64 {
534 return Err(overflow());
535 }
536 if f + 1.0 < -(MAX_DISPLAY_SCALE as f64) {
537 return Ok(Var::zero(MAX_DISPLAY_SCALE));
538 }
539 let rscale = result_scale(f as i64, &[self.dscale, exp_dscale]);
540 match exp {
541 0 => {
542 let mut one = Var::int(1);
543 one.dscale = rscale;
544 return Ok(one);
545 }
546 1 => {
547 let mut result = self.clone();
548 result.round(rscale);
549 return Ok(result);
550 }
551 -1 => return Var::int(1).div_round(self, rscale, true, true),
552 2 => return Ok(self.mul_round(self, rscale)),
553 _ => {}
554 }
555 if self.is_zero() {
556 if exp < 0 {
557 return Err(division_by_zero());
558 }
559 return Ok(Var::zero(rscale));
560 }
561 let sig_digits = 1 + rscale + f as i64 + f64::from(exp).abs().ln() as i64 + 8;
562 let mut negative = exp < 0;
563 let mut mask = exp.unsigned_abs();
564 let mut base_prod = self.clone();
565 let mut result = if mask & 1 == 1 { self.clone() } else { Var::int(1) };
566 loop {
567 mask >>= 1;
568 if mask == 0 {
569 break;
570 }
571 let local_rscale =
572 (sig_digits - 2 * base_prod.weight * DEC_DIGITS).min(2 * base_prod.dscale).max(0);
573 base_prod = base_prod.mul_round(&base_prod, local_rscale);
574 if mask & 1 == 1 {
575 let local_rscale = (sig_digits - (base_prod.weight + result.weight) * DEC_DIGITS)
576 .min(base_prod.dscale + result.dscale)
577 .max(0);
578 result = base_prod.mul_round(&result, local_rscale);
579 }
580 if base_prod.weight > WEIGHT_MAX || result.weight > WEIGHT_MAX {
582 if !negative {
583 return Err(overflow());
584 }
585 result = Var::zero(0);
586 negative = false;
587 break;
588 }
589 }
590 if negative {
591 return Var::int(1).div_round(&result, rscale, true, false);
592 }
593 result.round(rscale);
594 Ok(result)
595 }
596}
597
598fn isqrt(n: &Var) -> Var {
600 let len = n.weight + 1;
601 let (top, shift) = if len % 2 == 1 {
602 (i64::from(n.digit(n.weight)), (len - 1) / 2)
603 } else {
604 (
605 i64::from(n.digit(n.weight)) * i64::from(NBASE) + i64::from(n.digit(n.weight - 1)),
606 (len - 2) / 2,
607 )
608 };
609 let mut x = Var::int((top as f64).sqrt() as i64 + 1);
610 x.weight += shift;
611 let two = Var::int(2);
612 loop {
613 let y = x.add(&n.div(&x, 0, false)).div(&two, 0, false);
614 if y.cmp_abs(&x) != Ordering::Less {
615 return x;
616 }
617 x = y;
618 }
619}
620
621impl Numeric {
622 fn var(&self) -> Var {
623 Var::from(self)
624 }
625
626 fn is_zero(&self) -> bool {
627 self.sign.is_finite() && self.digits.is_empty()
628 }
629
630 fn signum(&self) -> i32 {
632 match self.sign {
633 NumericSign::Negative | NumericSign::NegativeInfinity => -1,
634 _ if self.is_zero() => 0,
635 _ => 1,
636 }
637 }
638
639 pub fn sqrt(&self) -> Result<Numeric, TypeError> {
641 match self.sign {
642 NumericSign::NegativeInfinity => {
643 return Err(power_error("cannot take square root of a negative number"));
644 }
645 NumericSign::NaN | NumericSign::Infinity => return Ok(self.clone()),
646 _ => {}
647 }
648 let arg = self.var();
649 if arg.cmp(&Var::zero(0)) == Ordering::Less {
650 return Err(power_error("cannot take square root of a negative number"));
651 }
652 let sweight = arg.weight * DEC_DIGITS / 2 + 1;
653 let rscale = result_scale(sweight, &[arg.dscale]);
654 arg.sqrt(rscale).make()
655 }
656
657 pub fn moment(
659 n: i64,
660 sum: &Numeric,
661 squares: &Numeric,
662 sample: bool,
663 root: bool,
664 ) -> Result<Numeric, TypeError> {
665 let count = Var::int(n);
666 let sum = sum.var();
667 let rscale = sum.dscale * 2;
669 let mut sum_sq = sum.mul(&sum);
670 sum_sq.dscale = rscale;
671 let mut scaled = count.mul(&squares.var());
672 scaled.dscale = rscale;
673 let numerator = scaled.sub(&sum_sq);
674 if numerator.cmp(&Var::zero(0)) != Ordering::Greater {
675 return Ok(Numeric::from_integer(0));
677 }
678 let mut denominator = count.mul(&Var::int(if sample { n - 1 } else { n }));
679 denominator.dscale = 0;
680 let rscale = select_div_scale(&numerator, &denominator);
681 let variance = numerator.div(&denominator, rscale, true);
682 if root { variance.sqrt(rscale).make() } else { variance.make() }
683 }
684
685 pub fn exp(&self) -> Result<Numeric, TypeError> {
687 match self.sign {
688 NumericSign::NegativeInfinity => return Var::zero(0).make(),
689 NumericSign::NaN | NumericSign::Infinity => return Ok(self.clone()),
690 _ => {}
691 }
692 let arg = self.var();
693 let val = (arg.to_f64() * LOG10_E).clamp(-2000.0, 2000.0);
694 let rscale = result_scale(val as i64, &[arg.dscale]);
695 arg.exp(rscale)?.make()
696 }
697
698 pub fn ln(&self) -> Result<Numeric, TypeError> {
700 match self.sign {
701 NumericSign::NegativeInfinity => {
702 return Err(log_error("cannot take logarithm of a negative number"));
703 }
704 NumericSign::NaN | NumericSign::Infinity => return Ok(self.clone()),
705 _ => {}
706 }
707 let arg = self.var();
708 let rscale = result_scale(arg.estimate_ln_dweight(), &[arg.dscale]);
709 arg.ln(rscale)?.make()
710 }
711
712 pub fn log(&self, num: &Numeric) -> Result<Numeric, TypeError> {
714 if !self.sign.is_finite() || !num.sign.is_finite() {
715 if self.sign == NumericSign::NaN || num.sign == NumericSign::NaN {
716 return Ok(Numeric::NAN);
717 }
718 if self.signum() < 0 || num.signum() < 0 {
719 return Err(log_error("cannot take logarithm of a negative number"));
720 }
721 if self.signum() == 0 || num.signum() == 0 {
722 return Err(log_error("cannot take logarithm of zero"));
723 }
724 if self.sign == NumericSign::Infinity {
725 if num.sign == NumericSign::Infinity {
726 return Ok(Numeric::NAN);
727 }
728 return Var::zero(0).make();
729 }
730 return Ok(Numeric::INFINITY);
731 }
732 self.var().log(&num.var())?.make()
733 }
734
735 pub fn power(&self, exp: &Numeric) -> Result<Numeric, TypeError> {
737 use NumericSign::{Infinity, NaN, NegativeInfinity};
738 let one = || Var::int(1).make();
739 let zero = || Var::zero(0).make();
740 if !self.sign.is_finite() || !exp.sign.is_finite() {
741 if self.sign == NaN {
742 if exp.is_zero() {
743 return one();
744 }
745 return Ok(Numeric::NAN);
746 }
747 if exp.sign == NaN {
748 if self.sign.is_finite() && self.var().cmp(&Var::int(1)) == Ordering::Equal {
749 return one();
750 }
751 return Ok(Numeric::NAN);
752 }
753 let (sign1, sign2) = (self.signum(), exp.signum());
754 if sign1 == 0 && sign2 < 0 {
755 return Err(power_error("zero raised to a negative power is undefined"));
756 }
757 if sign1 < 0 && exp.sign.is_finite() && !exp.var().is_integral() {
758 return Err(power_error(
759 "a negative number raised to a non-integer power yields a complex result",
760 ));
761 }
762 if self.sign.is_finite() && self.var().cmp(&Var::int(1)) == Ordering::Equal {
763 return one();
764 }
765 if sign2 == 0 {
766 return one();
767 }
768 if sign1 == 0 && sign2 > 0 {
769 return zero();
770 }
771 if !exp.sign.is_finite() {
772 let above_one = if self.sign.is_finite() {
773 let base = self.var();
774 if base.cmp(&Var::int(-1)) == Ordering::Equal {
775 return one();
776 }
777 base.cmp_abs(&Var::int(1)) == Ordering::Greater
778 } else {
779 true
780 };
781 return if above_one == (sign2 > 0) { Ok(Numeric::INFINITY) } else { zero() };
782 }
783 if self.sign == Infinity {
784 return if sign2 > 0 { Ok(Numeric::INFINITY) } else { zero() };
785 }
786 debug_assert_eq!(self.sign, NegativeInfinity);
787 if sign2 < 0 {
788 return zero();
789 }
790 let e = exp.var();
791 let odd = e.digits.len() as i64 == e.weight + 1
792 && e.digits.last().is_some_and(|d| d & 1 == 1);
793 return Ok(if odd { Numeric::NEGATIVE_INFINITY } else { Numeric::INFINITY });
794 }
795 if self.signum() == 0 && exp.signum() < 0 {
796 return Err(power_error("zero raised to a negative power is undefined"));
797 }
798 self.var().power(&exp.var())?.make()
799 }
800}
801
802const FACTORIAL_MAX: i64 = 32177;
804
805impl Numeric {
806 pub fn div_trunc(&self, other: &Numeric) -> Result<Numeric, TypeError> {
808 use NumericSign::{Infinity, NaN, NegativeInfinity};
809 if !self.sign.is_finite() || !other.sign.is_finite() {
810 if self.sign == NaN || other.sign == NaN {
811 return Ok(Numeric::NAN);
812 }
813 if !self.sign.is_finite() {
814 if !other.sign.is_finite() {
815 return Ok(Numeric::NAN);
816 }
817 let negative = (self.sign == NegativeInfinity) != (other.signum() < 0);
818 return match other.signum() {
819 0 => Err(division_by_zero()),
820 _ if negative => Ok(Numeric::NEGATIVE_INFINITY),
821 _ => Ok(Numeric::special(Infinity)),
822 };
823 }
824 return Var::zero(0).make();
825 }
826 self.var().div_round(&other.var(), 0, false, true)?.make()
827 }
828
829 pub fn gcd(&self, other: &Numeric) -> Result<Numeric, TypeError> {
831 if !self.sign.is_finite() || !other.sign.is_finite() {
832 return Ok(Numeric::NAN);
833 }
834 gcd(&self.var(), &other.var()).make()
835 }
836
837 pub fn lcm(&self, other: &Numeric) -> Result<Numeric, TypeError> {
839 if !self.sign.is_finite() || !other.sign.is_finite() {
840 return Ok(Numeric::NAN);
841 }
842 let (x, y) = (self.var(), other.var());
843 let mut result = if x.is_zero() || y.is_zero() {
844 Var::zero(0)
845 } else {
846 let mut result = y.mul(&x.div(&gcd(&x, &y), 0, false));
847 result.sign = NumericSign::Positive;
848 result
849 };
850 result.dscale = x.dscale.max(y.dscale);
851 result.make()
852 }
853
854 pub fn factorial(n: i64) -> Result<Numeric, TypeError> {
856 if n < 0 {
857 return Err(TypeError::new(
858 SqlState::NUMERIC_VALUE_OUT_OF_RANGE,
859 "factorial of a negative number is undefined".to_string(),
860 ));
861 }
862 if n > FACTORIAL_MAX {
863 return Err(overflow());
864 }
865 let mut result = Var::int(n.max(1));
866 for k in (2..n).rev() {
867 result = result.mul(&Var::int(k));
868 }
869 result.dscale = 0;
870 result.make()
871 }
872
873 pub fn scale(&self) -> Option<i32> {
875 self.sign.is_finite().then_some(i32::from(self.dscale))
876 }
877
878 pub fn min_scale(&self) -> Option<i32> {
880 self.sign.is_finite().then(|| min_scale(&self.var()) as i32)
881 }
882
883 pub fn trim_scale(&self) -> Numeric {
885 if !self.sign.is_finite() {
886 return self.clone();
887 }
888 let mut var = self.var();
889 var.dscale = min_scale(&var);
890 var.make().unwrap_or_else(|_| self.clone())
891 }
892
893 pub fn width_bucket(
895 &self,
896 low: &Numeric,
897 high: &Numeric,
898 count: i32,
899 ) -> Result<i32, TypeError> {
900 let bucket_error = |message: &str| {
901 TypeError::new(
902 SqlState::INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION,
903 message.to_string(),
904 )
905 };
906 if count <= 0 {
907 return Err(bucket_error("count must be greater than zero"));
908 }
909 if !low.sign.is_finite() || !high.sign.is_finite() {
910 if low.sign == NumericSign::NaN || high.sign == NumericSign::NaN {
911 return Err(bucket_error("lower and upper bounds cannot be NaN"));
912 }
913 return Err(bucket_error("lower and upper bounds must be finite"));
914 }
915 let past = i64::from(count) + 1;
916 let bucket = match low.compare(high) {
917 Ordering::Equal => return Err(bucket_error("lower bound cannot equal upper bound")),
918 Ordering::Less if self.compare(low) == Ordering::Less => 0,
919 Ordering::Less if self.compare(high) != Ordering::Less => past,
920 Ordering::Greater if self.compare(low) == Ordering::Greater => 0,
921 Ordering::Greater if self.compare(high) != Ordering::Greater => past,
922 _ => {
923 let (x, a, b) = (self.var(), low.var(), high.var());
925 let offset = x.sub(&a).mul(&Var::int(i64::from(count)));
926 let bucket = offset.div(&b.sub(&a), 0, false).add(&Var::int(1));
927 bucket.to_i64().unwrap_or(i64::MAX)
928 }
929 };
930 i32::try_from(bucket).map_err(|_| {
931 TypeError::new(SqlState::NUMERIC_VALUE_OUT_OF_RANGE, "integer out of range".to_string())
932 })
933 }
934}
935
936fn parameter_error(message: &str) -> TypeError {
937 TypeError::new(SqlState::INVALID_PARAMETER_VALUE, message.to_string())
938}
939
940impl Numeric {
941 pub fn random(prng: &mut Prng, rmin: &Numeric, rmax: &Numeric) -> Result<Numeric, TypeError> {
943 for (bound, name) in [(rmin, "lower"), (rmax, "upper")] {
944 match bound.sign {
945 NumericSign::NaN => {
946 return Err(parameter_error(&format!("{name} bound cannot be NaN")));
947 }
948 NumericSign::Infinity | NumericSign::NegativeInfinity => {
949 return Err(parameter_error(&format!("{name} bound cannot be infinity")));
950 }
951 _ => {}
952 }
953 }
954 random_var(prng, &rmin.var(), &rmax.var())?.make()
955 }
956}
957
958#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap)]
960fn random_var(prng: &mut Prng, rmin: &Var, rmax: &Var) -> Result<Var, TypeError> {
961 let rscale = rmin.dscale.max(rmax.dscale);
962 let rlen = rmax.sub(rmin);
963 if !rlen.is_zero() && rlen.sign == NumericSign::Negative {
964 return Err(parameter_error("lower bound must be less than or equal to upper bound"));
965 }
966 if rlen.is_zero() {
967 let mut result = rmin.clone();
968 result.dscale = rscale;
969 return Ok(result);
970 }
971 let frac_ndigits = ((rscale + DEC_DIGITS - 1) / DEC_DIGITS) as usize;
972 let res_ndigits = (rlen.weight + 1 + frac_ndigits as i64) as usize;
973 let pow10 = 10u64.pow((frac_ndigits as i64 * DEC_DIGITS - rscale) as u32);
975 let nbase = NBASE as u64;
976 let mut rlen64 = rlen.digits[0] as u64;
978 let mut rlen64_ndigits = 1;
979 while rlen64_ndigits < res_ndigits && rlen64_ndigits < 4 {
980 rlen64 *= nbase;
981 if let Some(&d) = rlen.digits.get(rlen64_ndigits) {
982 rlen64 += d as u64;
983 }
984 rlen64_ndigits += 1;
985 }
986 let whole_ndigits = if pow10 == 1 { res_ndigits } else { res_ndigits - 1 };
987 loop {
988 let mut digits = vec![0i32; res_ndigits];
989 let mut rand = if rlen64_ndigits == res_ndigits && pow10 != 1 {
990 prng.uint64_range(0, rlen64 / pow10) * pow10
991 } else {
992 prng.uint64_range(0, rlen64)
993 };
994 for d in digits[..rlen64_ndigits].iter_mut().rev() {
995 *d = (rand % nbase) as i32;
996 rand /= nbase;
997 }
998 let mut i = rlen64_ndigits;
999 while i + 3 < whole_ndigits {
1000 let mut rand = prng.uint64_range(0, nbase * nbase * nbase * nbase - 1);
1001 for d in &mut digits[i..i + 4] {
1002 *d = (rand % nbase) as i32;
1003 rand /= nbase;
1004 }
1005 i += 4;
1006 }
1007 while i < whole_ndigits {
1008 digits[i] = prng.uint64_range(0, nbase - 1) as i32;
1009 i += 1;
1010 }
1011 if i < res_ndigits {
1012 digits[i] = (prng.uint64_range(0, nbase / pow10 - 1) * pow10) as i32;
1013 }
1014 let mut result =
1015 Var { sign: NumericSign::Positive, weight: rlen.weight, dscale: rscale, digits };
1016 result.strip();
1017 if result.cmp(&rlen) != Ordering::Greater {
1018 return Ok(result.add(rmin));
1019 }
1020 }
1021}
1022
1023fn gcd(x: &Var, y: &Var) -> Var {
1025 let dscale = x.dscale.max(y.dscale);
1026 let (mut a, mut b) = if x.cmp_abs(y) == Ordering::Less {
1027 (y.clone(), x.clone())
1028 } else {
1029 (x.clone(), y.clone())
1030 };
1031 while !b.is_zero() && a.cmp_abs(&b) != Ordering::Equal {
1032 let rest = a.rem(&b);
1033 a = b;
1034 b = rest;
1035 }
1036 a.sign = NumericSign::Positive;
1037 a.dscale = dscale;
1038 a
1039}
1040
1041fn min_scale(var: &Var) -> i64 {
1043 let Some(last) = var.digits.iter().rposition(|&d| d != 0) else { return 0 };
1044 let mut scale = (last as i64 - var.weight) * DEC_DIGITS;
1045 if scale <= 0 {
1046 return 0;
1047 }
1048 let mut digit = var.digits[last];
1049 while digit % 10 == 0 {
1050 scale -= 1;
1051 digit /= 10;
1052 }
1053 scale
1054}