1use crate::CellValue;
13use improv_core_model::FuncId;
14
15pub mod err {
18 pub const NULL: u8 = 1;
19 pub const DIV0: u8 = 2;
20 pub const VALUE: u8 = 3;
21 pub const REF: u8 = 4;
22 pub const NAME: u8 = 5;
23 pub const NUM: u8 = 6;
24 pub const NA: u8 = 7;
25}
26
27pub(crate) fn e(code: u8) -> CellValue {
28 CellValue::Err(code)
29}
30
31pub(crate) fn num(x: f64) -> CellValue {
33 if x.is_finite() {
34 CellValue::num(x)
35 } else {
36 e(err::NUM)
37 }
38}
39
40mod date;
41mod dist_extra;
42mod engineering;
43mod financial;
44mod math_extra;
45mod options;
46pub(crate) mod statistical;
47
48fn inspects_errors(id: u32) -> bool {
51 matches!(id, 50 | 51 | 52 | 55) || date::inspects_errors(id)
52}
53
54pub fn eval(func: FuncId, args: &[CellValue]) -> CellValue {
57 if !inspects_errors(func.0) {
58 if let Some(bad) = args.iter().find(|a| matches!(a, CellValue::Err(_))) {
59 return bad.clone();
60 }
61 }
62 match eval_ok(func.0, args) {
63 Ok(v) => v,
64 Err(code) => e(code),
65 }
66}
67
68pub(crate) type R = Result<CellValue, u8>;
69
70pub(crate) fn n(args: &[CellValue], i: usize) -> Result<f64, u8> {
71 match args.get(i) {
72 Some(CellValue::Num(b)) => Ok(f64::from_bits(*b)),
73 Some(CellValue::Bool(b)) => Ok(if *b { 1.0 } else { 0.0 }),
74 Some(CellValue::Date(ms)) => Ok(*ms as f64),
75 _ => Err(err::VALUE),
76 }
77}
78
79pub(crate) fn n_or(args: &[CellValue], i: usize, default: f64) -> Result<f64, u8> {
81 if args.len() > i {
82 n(args, i)
83 } else {
84 Ok(default)
85 }
86}
87
88#[allow(dead_code)]
90pub(crate) const DAY_MS: i64 = 86_400_000;
92#[allow(dead_code)]
94pub(crate) const SERIAL_EPOCH_MS: i64 = -2_209_161_600_000;
98
99#[allow(dead_code)]
101pub(crate) fn d(args: &[CellValue], i: usize) -> Result<i64, u8> {
104 match args.get(i) {
105 Some(CellValue::Date(ms)) => Ok(*ms),
106 Some(CellValue::Num(b)) => {
107 let serial = f64::from_bits(*b);
108 let ms = serial * DAY_MS as f64;
109 if !ms.is_finite() || ms.abs() > 1e16 {
110 return Err(err::NUM);
111 }
112 Ok(SERIAL_EPOCH_MS + ms.round() as i64)
113 }
114 _ => Err(err::VALUE),
115 }
116}
117
118#[allow(dead_code)]
120pub(crate) fn serial(ms: i64) -> f64 {
122 (ms - SERIAL_EPOCH_MS) as f64 / DAY_MS as f64
123}
124
125pub(crate) fn t(args: &[CellValue], i: usize) -> Result<String, u8> {
126 match args.get(i) {
127 Some(v) => text_of(v),
128 None => Err(err::VALUE),
129 }
130}
131
132pub(crate) fn b(args: &[CellValue], i: usize) -> Result<bool, u8> {
133 match args.get(i) {
134 Some(CellValue::Bool(b)) => Ok(*b),
135 Some(CellValue::Num(x)) => Ok(f64::from_bits(*x) != 0.0),
136 _ => Err(err::VALUE),
137 }
138}
139
140pub(crate) fn text_of(v: &CellValue) -> Result<String, u8> {
142 Ok(match v {
143 CellValue::Text(s) => s.clone(),
144 CellValue::Num(bits) => crate::display_number(f64::from_bits(*bits)),
145 CellValue::Bool(true) => "TRUE".into(),
146 CellValue::Bool(false) => "FALSE".into(),
147 CellValue::Date(_) => v.to_string(),
148 CellValue::Err(c) => return Err(*c),
149 })
150}
151
152pub(crate) fn ok_num(x: f64) -> R {
153 Ok(num(x))
154}
155
156pub(crate) fn ok_text(s: String) -> R {
157 Ok(CellValue::Text(s))
158}
159
160pub(crate) fn domain(ok: bool) -> Result<(), u8> {
161 if ok {
162 Ok(())
163 } else {
164 Err(err::NUM)
165 }
166}
167
168pub(crate) fn count(x: f64) -> Result<u64, u8> {
170 domain((0.0..1e15).contains(&x))?;
171 Ok(x.trunc() as u64)
172}
173
174pub(crate) fn nums(args: &[CellValue]) -> Result<Vec<f64>, u8> {
175 (0..args.len()).map(|i| n(args, i)).collect()
176}
177
178pub(crate) fn bools(args: &[CellValue]) -> Result<Vec<bool>, u8> {
179 (0..args.len()).map(|i| b(args, i)).collect()
180}
181
182fn eval_ok(id: u32, a: &[CellValue]) -> R {
184 match id {
185 56..=79 | 330..=399 | 400..=499 => date::eval(id, a),
186 160..=199 | 500..=699 => statistical::eval(id, a),
187 700..=899 => financial::eval(id, a),
188 1300..=1449 => engineering::eval(id, a),
189 1450..=1549 => math_extra::eval(id, a),
190 1550..=1749 => dist_extra::eval(id, a),
191 1750..=1849 => options::eval(id, a),
192 _ => eval_core(id, a),
193 }
194}
195
196fn eval_core(id: u32, a: &[CellValue]) -> R {
197 use std::f64::consts::PI;
198 Ok(match id {
199 20 => num(nums(a)?.into_iter().fold(f64::INFINITY, f64::min)),
201 21 => num(nums(a)?.into_iter().fold(f64::NEG_INFINITY, f64::max)),
202 22 => num(nums(a)?.iter().sum()),
203 23 => {
204 let v = nums(a)?;
205 num(v.iter().sum::<f64>() / v.len() as f64)
206 }
207 24 => num(nums(a)?.iter().product()),
208 25 => num(nums(a)?.iter().map(|x| x * x).sum()),
209 26 => CellValue::Bool(bools(a)?.iter().all(|x| *x)),
210 27 => CellValue::Bool(bools(a)?.iter().any(|x| *x)),
211 28 => CellValue::Bool(bools(a)?.iter().filter(|x| **x).count() % 2 == 1),
212 38 => {
214 let (x, lo, hi) = (n(a, 0)?, n(a, 1)?, n(a, 2)?);
215 let inclusive = if a.len() > 3 { b(a, 3)? } else { true };
216 CellValue::Bool(if inclusive {
217 lo <= x && x <= hi
218 } else {
219 lo < x && x < hi
220 })
221 }
222 39 => CellValue::Bool(true),
223 40 => CellValue::Bool(false),
224 50 => CellValue::Bool(matches!(a[0], CellValue::Err(_))),
226 51 => CellValue::Bool(matches!(a[0], CellValue::Err(c) if c != err::NA)),
227 52 => CellValue::Bool(matches!(a[0], CellValue::Err(err::NA))),
228 53 => return Err(err::NA),
229 54 => {
230 let code = t(a, 0)?;
231 let kind = improv_core_model::ValueErrorKind::from_code(&code).ok_or(err::VALUE)?;
232 return Err(kind.error_type().unwrap_or(err::VALUE));
233 }
234 55 => match a[0] {
235 CellValue::Err(c) if c > 0 => CellValue::num(f64::from(c)),
236 _ => return Err(err::NA),
237 },
238 10 => num(n(a, 0)?.abs()),
240 15 => num(-n(a, 0)?),
241 100 => {
242 let x = n(a, 0)?;
243 num(if x > 0.0 {
244 1.0
245 } else if x < 0.0 {
246 -1.0
247 } else {
248 0.0
249 })
250 }
251 14 => {
252 let x = n(a, 0)?;
253 domain(x >= 0.0)?;
254 num(x.sqrt())
255 }
256 101 => {
257 let x = n(a, 0)?;
258 domain(x >= 0.0)?;
259 num((x * PI).sqrt())
260 }
261 102 => num(n(a, 0)?.exp()),
262 103 => num(n(a, 0)?.exp_m1()),
263 104 => {
264 let x = n(a, 0)?;
265 domain(x > 0.0)?;
266 num(x.ln())
267 }
268 105 => {
269 let x = n(a, 0)?;
270 domain(x > -1.0)?;
271 num(x.ln_1p())
272 }
273 106 => {
274 let (x, base) = (n(a, 0)?, n_or(a, 1, 10.0)?);
275 domain(x > 0.0 && base > 0.0)?;
276 if base == 1.0 {
277 return Err(err::DIV0);
278 }
279 num(if base == 10.0 {
280 x.log10()
281 } else {
282 x.ln() / base.ln()
283 })
284 }
285 107 => {
286 let x = n(a, 0)?;
287 domain(x > 0.0)?;
288 num(x.log10())
289 }
290 108 => {
291 let x = n(a, 0)?;
292 domain(x > 0.0)?;
293 num(x.log2())
294 }
295 109 => return power(n(a, 0)?, n(a, 1)?),
296 110 => {
297 let (x, d) = (n(a, 0)?, n(a, 1)?);
298 if d == 0.0 {
299 return Err(err::DIV0);
300 }
301 num(x - d * (x / d).floor())
302 }
303 111 => {
304 let (x, d) = (n(a, 0)?, n(a, 1)?);
305 if d == 0.0 {
306 return Err(err::DIV0);
307 }
308 num((x / d).trunc())
309 }
310 112 => CellValue::num(PI),
311 113 => num(n(a, 0)?.to_degrees()),
312 114 => num(n(a, 0)?.to_radians()),
313 115 => num(n(a, 0)?.sin()),
314 116 => num(n(a, 0)?.cos()),
315 117 => num(n(a, 0)?.tan()),
316 118 => {
317 let x = n(a, 0)?;
318 domain((-1.0..=1.0).contains(&x))?;
319 num(x.asin())
320 }
321 119 => {
322 let x = n(a, 0)?;
323 domain((-1.0..=1.0).contains(&x))?;
324 num(x.acos())
325 }
326 120 => num(n(a, 0)?.atan()),
327 121 => {
328 let (x, y) = (n(a, 0)?, n(a, 1)?);
329 if x == 0.0 && y == 0.0 {
330 return Err(err::DIV0);
331 }
332 num(y.atan2(x))
333 }
334 122 => num(n(a, 0)?.sinh()),
335 123 => num(n(a, 0)?.cosh()),
336 124 => num(n(a, 0)?.tanh()),
337 125 => num(n(a, 0)?.asinh()),
338 126 => {
339 let x = n(a, 0)?;
340 domain(x >= 1.0)?;
341 num(x.acosh())
342 }
343 127 => {
344 let x = n(a, 0)?;
345 domain(x > -1.0 && x < 1.0)?;
346 num(x.atanh())
347 }
348 128 => recip(trig_arg(n(a, 0)?)?.cos())?,
349 129 => recip(trig_arg(n(a, 0)?)?.sin())?,
350 130 => recip(trig_arg(n(a, 0)?)?.tan())?,
351 131 => recip(n(a, 0)?.cosh())?,
352 132 => recip(n(a, 0)?.sinh())?,
353 133 => recip(n(a, 0)?.tanh())?,
354 134 => num(PI / 2.0 - n(a, 0)?.atan()),
355 135 => {
356 let x = n(a, 0)?;
357 domain(x.abs() > 1.0)?;
358 num(0.5 * ((x + 1.0) / (x - 1.0)).ln())
359 }
360 136 => num(sin_pi(n(a, 0)?)),
361 137 => num(cos_pi(n(a, 0)?)),
362 138 => {
363 let x = n(a, 0)?;
364 let c = cos_pi(x);
365 domain(c != 0.0)?;
366 num(sin_pi(x) / c)
367 }
368 139 => {
369 let x = n(a, 0)?;
370 let s = sin_pi(x);
371 domain(s != 0.0)?;
372 num(cos_pi(x) / s)
373 }
374 140 => num(nums(a)?.into_iter().fold(0.0, f64::hypot)),
375 141 => num(fact(count(n(a, 0)?)?)),
376 142 => {
377 let x = n(a, 0)?;
378 domain(x >= 0.0)?;
379 let k = x.trunc() as i64;
380 num(product((2 - k % 2..=k).rev().step_by(2).map(|i| i as f64)))
381 }
382 143 => {
383 let (nn, k) = (count(n(a, 0)?)?, count(n(a, 1)?)?);
384 domain(k <= nn)?;
385 num(combin(nn, k))
386 }
387 144 => {
388 let (nn, k) = (count(n(a, 0)?)?, count(n(a, 1)?)?);
389 if nn == 0 && k == 0 {
390 CellValue::num(1.0)
391 } else {
392 domain(nn > 0)?;
393 num(combin(nn + k - 1, k))
394 }
395 }
396 145 => {
397 let (nn, k) = (count(n(a, 0)?)?, count(n(a, 1)?)?);
398 domain(k <= nn)?;
399 num(product(((nn - k + 1)..=nn).map(|i| i as f64)))
400 }
401 146 => {
402 let (nn, k) = (count(n(a, 0)?)?, count(n(a, 1)?)?);
403 num((nn as f64).powf(k as f64))
404 }
405 147 => {
406 let v = nums(a)?;
407 let mut g = 0u64;
408 for x in v {
409 g = gcd(g, count(x)?);
410 }
411 CellValue::num(g as f64)
412 }
413 148 => {
414 let v = nums(a)?;
415 let mut l = 1u64;
416 for x in v {
417 let k = count(x)?;
418 if k == 0 {
419 return Ok(CellValue::num(0.0));
420 }
421 l = improv_verified::gcd::lcm_below(l, k, 1 << 53).ok_or(err::NUM)?;
423 }
424 CellValue::num(l as f64)
425 }
426 149 => {
427 let v = nums(a)?;
428 let mut total = 0u64;
430 let mut r = 1f64;
431 for x in v {
432 let k = count(x)?;
433 total += k;
434 r *= combin(total, k);
435 }
436 num(r.round())
437 }
438 150 => {
439 let v = nums(a)?;
440 num(v[1..].iter().fold(v[0], |acc, x| acc - x))
441 }
442 151 => {
443 let v = nums(a)?;
444 if v.iter().any(|x| *x < 0.0) {
445 return Err(err::VALUE);
446 }
447 if v.contains(&0.0) {
448 return Ok(CellValue::num(0.0));
449 }
450 num(1.0 / v.iter().map(|x| 1.0 / x).sum::<f64>())
451 }
452 11 => num(round_to(n(a, 0)?, n_or(a, 1, 0.0)?, Dir::HalfAway)),
454 200 => num(round_to(n(a, 0)?, n_or(a, 1, 0.0)?, Dir::Away)),
455 201 | 203 => num(round_to(n(a, 0)?, n_or(a, 1, 0.0)?, Dir::Toward)),
456 202 => {
457 let (x, d) = (n(a, 0)?, n(a, 1)?);
458 domain(d >= 1.0)?;
459 if x == 0.0 {
460 CellValue::num(0.0)
461 } else {
462 let digits = d.trunc() - 1.0 - x.abs().log10().floor();
463 num(round_to(x, digits, Dir::HalfAway))
464 }
465 }
466 204 => num(n(a, 0)?.floor()),
467 13 => num(n(a, 0)?.ceil()),
468 12 => {
469 let (x, sig) = (n(a, 0)?, n_or(a, 1, 1.0)?);
470 floor_xl(x, sig)?
471 }
472 205 => {
473 let (x, sig) = (n(a, 0)?, n_or(a, 1, 1.0)?);
474 ceiling_xl(x, sig)?
475 }
476 206 => {
477 let (x, sig, mode) = (n(a, 0)?, n_or(a, 1, 1.0)?, n_or(a, 2, 0.0)?);
478 let sig = sig.abs();
479 if sig == 0.0 {
480 return Ok(CellValue::num(0.0));
481 }
482 num(if x < 0.0 && mode != 0.0 {
483 sig15(clean(x / sig).ceil() * sig)
484 } else {
485 sig15(clean(x / sig).floor() * sig)
486 })
487 }
488 207 => {
489 let (x, sig, mode) = (n(a, 0)?, n_or(a, 1, 1.0)?, n_or(a, 2, 0.0)?);
490 let sig = sig.abs();
491 if sig == 0.0 {
492 return Ok(CellValue::num(0.0));
493 }
494 num(if x < 0.0 && mode != 0.0 {
495 sig15(clean(x / sig).floor() * sig)
496 } else {
497 sig15(clean(x / sig).ceil() * sig)
498 })
499 }
500 208 => {
501 let (x, sig) = (n(a, 0)?, n_or(a, 1, 1.0)?.abs());
502 if sig == 0.0 {
503 return Ok(CellValue::num(0.0));
504 }
505 num(sig15(clean(x / sig).floor() * sig))
506 }
507 209 | 210 => {
508 let (x, sig) = (n(a, 0)?, n_or(a, 1, 1.0)?.abs());
509 if sig == 0.0 {
510 return Ok(CellValue::num(0.0));
511 }
512 num(sig15(clean(x / sig).ceil() * sig))
513 }
514 211 => {
515 let (x, m) = (n(a, 0)?, n(a, 1)?);
516 if m == 0.0 {
517 return Ok(CellValue::num(0.0));
518 }
519 domain(x == 0.0 || (x > 0.0) == (m > 0.0))?;
520 num(sig15(round_to(x / m, 0.0, Dir::HalfAway) * m))
521 }
522 212 => {
523 let x = n(a, 0)?;
524 let r = (x.abs() / 2.0).ceil() * 2.0;
525 num(r.copysign(x))
526 }
527 213 => {
528 let x = n(a, 0)?;
529 let m = x.abs().ceil();
530 let r = if m % 2.0 == 1.0 { m } else { m + 1.0 };
531 num(if x < 0.0 { -r } else { r })
532 }
533 300 => {
535 let c = n(a, 0)?.trunc();
536 if !(1.0..=255.0).contains(&c) {
537 return Err(err::VALUE);
538 }
539 ok_text(char::from_u32(c as u32).ok_or(err::VALUE)?.to_string())?
541 }
542 301 => {
543 let c = n(a, 0)?.trunc();
544 if !(1.0..=1_114_111.0).contains(&c) {
545 return Err(err::VALUE);
546 }
547 ok_text(char::from_u32(c as u32).ok_or(err::VALUE)?.to_string())?
548 }
549 302 | 303 => {
550 let s = t(a, 0)?;
551 let c = s.chars().next().ok_or(err::VALUE)?;
552 CellValue::num(f64::from(c as u32))
553 }
554 304 => ok_text(t(a, 0)?.chars().filter(|c| (*c as u32) >= 32).collect())?,
555 305 | 306 => {
556 let mut s = String::new();
557 for v in a {
558 s.push_str(&text_of(v)?);
559 }
560 ok_text(s)?
561 }
562 307 => CellValue::Bool(t(a, 0)? == t(a, 1)?),
563 308 | 309 => {
564 let (find, text) = (t(a, 0)?, t(a, 1)?);
565 let start = n_or(a, 2, 1.0)?.trunc();
566 let chars: Vec<char> = text.chars().collect();
567 if start < 1.0 || start > chars.len() as f64 + 1.0 {
568 return Err(err::VALUE);
569 }
570 let from = start as usize - 1;
571 let hit = if id == 308 {
572 find_chars(&chars, &find.chars().collect::<Vec<_>>(), from)
573 } else {
574 search_chars(&chars, &find, from)
575 };
576 CellValue::num(hit.ok_or(err::VALUE)? as f64 + 1.0)
577 }
578 310 | 311 => {
579 let s: Vec<char> = t(a, 0)?.chars().collect();
580 let k = n_or(a, 1, 1.0)?;
581 if k < 0.0 {
582 return Err(err::VALUE);
583 }
584 let k = (k.trunc() as usize).min(s.len());
585 let part = if id == 310 {
586 &s[..k]
587 } else {
588 &s[s.len() - k..]
589 };
590 ok_text(part.iter().collect())?
591 }
592 312 => {
593 let s: Vec<char> = t(a, 0)?.chars().collect();
594 let (start, k) = (n(a, 1)?.trunc(), n(a, 2)?.trunc());
595 if start < 1.0 || k < 0.0 {
596 return Err(err::VALUE);
597 }
598 let from = (start as usize - 1).min(s.len());
599 let to = from.saturating_add(k as usize).min(s.len());
600 ok_text(s[from..to].iter().collect())?
601 }
602 313 => CellValue::num(t(a, 0)?.chars().count() as f64),
603 314 => ok_text(t(a, 0)?.to_lowercase())?,
604 315 => ok_text(t(a, 0)?.to_uppercase())?,
605 316 => ok_text(proper(&t(a, 0)?))?,
606 317 => {
607 let s: Vec<char> = t(a, 0)?.chars().collect();
608 let (start, k, new) = (n(a, 1)?.trunc(), n(a, 2)?.trunc(), t(a, 3)?);
609 if start < 1.0 || k < 0.0 {
610 return Err(err::VALUE);
611 }
612 let from = (start as usize - 1).min(s.len());
613 let to = from.saturating_add(k as usize).min(s.len());
614 let mut out: String = s[..from].iter().collect();
615 out.push_str(&new);
616 out.extend(&s[to..]);
617 ok_text(out)?
618 }
619 318 => {
620 let (s, k) = (t(a, 0)?, n(a, 1)?);
621 if k < 0.0 || (s.chars().count() as f64) * k.trunc() > 32_767.0 {
622 return Err(err::VALUE);
623 }
624 ok_text(s.repeat(k.trunc() as usize))?
625 }
626 319 => {
627 let (s, old, new) = (t(a, 0)?, t(a, 1)?, t(a, 2)?);
628 if old.is_empty() {
629 return ok_text(s);
630 }
631 if a.len() > 3 {
632 let inst = n(a, 3)?.trunc();
633 if inst < 1.0 {
634 return Err(err::VALUE);
635 }
636 match s.match_indices(&old).nth(inst as usize - 1) {
637 Some((i, _)) => ok_text(format!("{}{new}{}", &s[..i], &s[i + old.len()..]))?,
638 None => ok_text(s)?,
639 }
640 } else {
641 ok_text(s.replace(&old, &new))?
642 }
643 }
644 320 => ok_text(
645 t(a, 0)?
646 .split(' ')
647 .filter(|w| !w.is_empty())
648 .collect::<Vec<_>>()
649 .join(" "),
650 )?,
651 321 => {
652 let s = t(a, 0)?;
653 num(parse_value(&s).ok_or(err::VALUE)?)
654 }
655 322 | 323 => text_before_after(id == 322, a)?,
656 324 => {
657 let s: Vec<char> = t(a, 0)?.chars().collect();
658 let fold = |v: &[char]| v.iter().map(|c| fold_char(*c)).collect::<Vec<_>>();
659 let hay = fold(&s);
660 let open = fold(&t(a, 1)?.chars().collect::<Vec<_>>());
661 let close = fold(&t(a, 2)?.chars().collect::<Vec<_>>());
662 let i = find_chars(&hay, &open, 0).ok_or(err::NA)? + open.len();
663 let j = find_chars(&hay, &close, i).ok_or(err::NA)?;
664 ok_text(s[i..j].iter().collect())?
665 }
666 325 => {
667 let hay: Vec<char> = t(a, 0)?.chars().map(fold_char).collect();
669 let needle: Vec<char> = t(a, 1)?.chars().map(fold_char).collect();
670 if needle.is_empty() {
671 return Err(err::VALUE);
672 }
673 let hits = hay
674 .windows(needle.len())
675 .filter(|w| *w == needle.as_slice())
676 .count();
677 CellValue::num(hits as f64)
678 }
679 _ => return Err(err::NAME),
680 })
681}
682
683pub(crate) fn date_plus_days(d: i64, days: f64) -> CellValue {
686 let ms = days * 86_400_000.0;
687 if !ms.is_finite() || ms.abs() > 1e17 {
688 return e(err::NUM);
689 }
690 d.checked_add(ms.round() as i64)
691 .filter(|v| chrono::DateTime::<chrono::Utc>::from_timestamp_millis(*v).is_some())
692 .map_or(e(err::NUM), CellValue::Date)
693}
694
695pub(crate) fn power(x: f64, y: f64) -> R {
698 if x == 0.0 && y < 0.0 {
699 return Err(err::DIV0);
700 }
701 if x < 0.0 && y.fract() != 0.0 {
702 return Err(err::NUM);
703 }
704 ok_num(x.powf(y))
705}
706
707fn trig_arg(x: f64) -> Result<f64, u8> {
709 domain(x.abs() < 134_217_728.0)?;
710 Ok(x)
711}
712
713pub(crate) fn fold_char(c: char) -> char {
716 c.to_lowercase().next().unwrap_or(c)
717}
718
719fn recip(d: f64) -> R {
720 if d == 0.0 {
721 return Err(err::DIV0);
722 }
723 ok_num(1.0 / d)
724}
725
726fn sin_pi(x: f64) -> f64 {
728 let r = x.rem_euclid(2.0);
729 if r.fract() == 0.0 {
730 return 0.0;
731 }
732 if r == 0.5 {
733 return 1.0;
734 }
735 if r == 1.5 {
736 return -1.0;
737 }
738 (std::f64::consts::PI * r).sin()
739}
740
741fn cos_pi(x: f64) -> f64 {
743 let r = x.rem_euclid(2.0);
744 if r == 0.5 || r == 1.5 {
745 return 0.0;
746 }
747 if r == 0.0 {
748 return 1.0;
749 }
750 if r == 1.0 {
751 return -1.0;
752 }
753 (std::f64::consts::PI * r).cos()
754}
755
756fn fact(k: u64) -> f64 {
757 product((1..=k).map(|i| i as f64))
758}
759
760fn product(factors: impl Iterator<Item = f64>) -> f64 {
763 let mut p = 1f64;
764 for x in factors {
765 p *= x;
766 if p.is_infinite() {
767 break;
768 }
769 }
770 p
771}
772
773fn combin(n: u64, k: u64) -> f64 {
774 let k = k.min(n - k);
775 let mut r = 1f64;
776 for i in 0..k {
778 r = r * (n - i) as f64 / (i + 1) as f64;
779 if r.is_infinite() {
780 break;
781 }
782 }
783 r.round()
784}
785
786use improv_verified::gcd::gcd;
788
789#[derive(Clone, Copy)]
790enum Dir {
791 HalfAway,
792 Away,
793 Toward,
794}
795
796fn round_to(x: f64, digits: f64, dir: Dir) -> f64 {
801 let d = digits.trunc().clamp(-308.0, 308.0) as i32;
802 let scale = 10f64.powi(d.abs());
803 let y = if d >= 0 { x * scale } else { x / scale };
804 let y = if y.abs() < 1e15 {
805 format!("{y:.14e}").parse::<f64>().unwrap_or(y)
806 } else {
807 y
808 };
809 let r = match dir {
810 Dir::HalfAway => y.round(),
811 Dir::Away => y.abs().ceil().copysign(y),
812 Dir::Toward => y.trunc(),
813 };
814 sig15(if d >= 0 { r / scale } else { r * scale })
815}
816
817fn floor_xl(x: f64, sig: f64) -> R {
820 if sig == 0.0 {
821 return if x == 0.0 {
822 Ok(CellValue::num(0.0))
823 } else {
824 Err(err::DIV0)
825 };
826 }
827 if x > 0.0 && sig < 0.0 {
828 return Err(err::NUM);
829 }
830 ok_num(sig15(clean(x / sig).floor() * sig))
831}
832
833fn ceiling_xl(x: f64, sig: f64) -> R {
835 if sig == 0.0 {
836 return Ok(CellValue::num(0.0));
837 }
838 if x > 0.0 && sig < 0.0 {
839 return Err(err::NUM);
840 }
841 ok_num(sig15(clean(x / sig).ceil() * sig))
842}
843
844fn sig15(x: f64) -> f64 {
848 if x == 0.0 || !x.is_finite() {
849 return x;
850 }
851 format!("{x:.14e}").parse().unwrap_or(x)
852}
853
854fn clean(q: f64) -> f64 {
859 sig15(q)
860}
861
862fn proper(s: &str) -> String {
863 let mut out = String::with_capacity(s.len());
864 let mut prev_letter = false;
865 for c in s.chars() {
866 if c.is_alphabetic() {
867 if prev_letter {
868 out.extend(c.to_lowercase());
869 } else {
870 out.extend(c.to_uppercase());
871 }
872 prev_letter = true;
873 } else {
874 out.push(c);
875 prev_letter = false;
876 }
877 }
878 out
879}
880
881pub(crate) fn find_chars(hay: &[char], needle: &[char], from: usize) -> Option<usize> {
882 if needle.is_empty() {
883 return Some(from);
884 }
885 (from..=hay.len().checked_sub(needle.len())?).find(|&i| hay[i..i + needle.len()] == *needle)
886}
887
888pub(crate) fn search_chars(hay: &[char], pattern: &str, from: usize) -> Option<usize> {
891 let lower: Vec<char> = hay.iter().flat_map(|c| c.to_lowercase()).collect();
892 if lower.len() != hay.len() {
893 return find_chars(hay, &pattern.chars().collect::<Vec<_>>(), from);
895 }
896 let pat: Vec<Pat> = {
897 let mut out = Vec::new();
898 let mut it = pattern.chars();
899 while let Some(c) = it.next() {
900 out.push(match c {
901 '~' => match it.next() {
902 Some(n) => Pat::Lit(n.to_lowercase().next().unwrap_or(n)),
903 None => Pat::Lit('~'),
904 },
905 '?' => Pat::One,
906 '*' => Pat::Many,
907 c => Pat::Lit(c.to_lowercase().next().unwrap_or(c)),
908 });
909 }
910 out
911 };
912 (from..=lower.len()).find(|&i| matches_at(&lower[i..], &pat))
913}
914
915#[derive(Clone, Copy)]
916enum Pat {
917 Lit(char),
918 One,
919 Many,
920}
921
922fn matches_at(s: &[char], pat: &[Pat]) -> bool {
924 let (mut si, mut pi) = (0, 0);
926 let mut star: Option<(usize, usize)> = None;
927 loop {
928 if pi == pat.len() {
929 return true;
930 }
931 match pat[pi] {
932 Pat::Many => {
933 star = Some((pi, si));
934 pi += 1;
935 continue;
936 }
937 Pat::One if si < s.len() => {
938 si += 1;
939 pi += 1;
940 continue;
941 }
942 Pat::Lit(c) if si < s.len() && s[si] == c => {
943 si += 1;
944 pi += 1;
945 continue;
946 }
947 _ => {}
948 }
949 match star {
950 Some((sp, ss)) if ss < s.len() => {
951 star = Some((sp, ss + 1));
952 pi = sp + 1;
953 si = ss + 1;
954 }
955 _ => return false,
956 }
957 }
958}
959
960fn parse_value(s: &str) -> Option<f64> {
963 let s = s.trim();
964 let (s, pct) = match s.strip_suffix('%') {
965 Some(rest) => (rest.trim_end(), true),
966 None => (s, false),
967 };
968 let cleaned: String = s.chars().filter(|c| *c != ',').collect();
969 if cleaned.is_empty()
970 || !cleaned
971 .chars()
972 .all(|c| c.is_ascii_digit() || matches!(c, '.' | '-' | '+' | 'e' | 'E'))
973 {
974 return None;
975 }
976 let v: f64 = cleaned.parse().ok()?;
977 Some(if pct { v / 100.0 } else { v })
978}
979
980fn text_before_after(before: bool, a: &[CellValue]) -> R {
985 let (s, delim) = (t(a, 0)?, t(a, 1)?);
986 let inst = n_or(a, 2, 1.0)?.trunc() as i64;
987 let insensitive = n_or(a, 3, 0.0)? != 0.0;
988 let match_end = n_or(a, 4, 0.0)? != 0.0;
989 let chars: Vec<char> = s.chars().collect();
990 if inst == 0 || inst.unsigned_abs() as usize > chars.len().max(1) {
991 return Err(err::VALUE);
992 }
993 let fold = |c: char| {
994 if insensitive {
995 c.to_lowercase().next().unwrap_or(c)
996 } else {
997 c
998 }
999 };
1000 let hay: Vec<char> = chars.iter().map(|c| fold(*c)).collect();
1001 let needle: Vec<char> = delim.chars().map(fold).collect();
1002 let mut hits: Vec<(usize, usize)> = Vec::new();
1004 if needle.is_empty() {
1005 hits.push((0, 0));
1006 hits.push((chars.len(), chars.len()));
1007 } else {
1008 let mut i = 0;
1009 while let Some(p) = find_chars(&hay, &needle, i) {
1010 hits.push((p, p + needle.len()));
1011 i = p + needle.len();
1012 }
1013 }
1014 if match_end {
1015 if inst > 0 {
1016 hits.push((chars.len(), chars.len()));
1017 } else {
1018 hits.insert(0, (0, 0));
1019 }
1020 }
1021 let pick = if inst > 0 {
1022 hits.get(inst as usize - 1)
1023 } else {
1024 hits.len()
1025 .checked_sub(inst.unsigned_abs() as usize)
1026 .and_then(|i| hits.get(i))
1027 };
1028 let Some(&(start, end)) = pick else {
1029 return match a.get(5) {
1030 Some(v) => Ok(v.clone()),
1031 None => Err(err::NA),
1032 };
1033 };
1034 let part: String = if before {
1035 chars[..start].iter().collect()
1036 } else {
1037 chars[end..].iter().collect()
1038 };
1039 ok_text(part)
1040}
1041
1042#[cfg(test)]
1043#[cfg_attr(coverage_nightly, coverage(off))]
1044mod tests {
1045 use super::*;
1046 use improv_core_model::functions::{all, Kind};
1047
1048 #[test]
1051 fn every_scalar_function_is_implemented() {
1052 for d in all().filter(|d| {
1054 d.kind == Kind::Scalar
1055 && d.category != improv_core_model::functions::Category::Dimensional
1056 }) {
1057 let args: Vec<CellValue> = (0..d.required.max(1).min(d.params.len().max(1)))
1058 .take(d.required)
1059 .map(|i| match d.param(i) {
1060 improv_core_model::functions::Arg::Text => CellValue::Text("ab".into()),
1061 improv_core_model::functions::Arg::Boolean => CellValue::Bool(true),
1062 _ => CellValue::num(1.0),
1063 })
1064 .collect();
1065 let v = eval(d.id, &args);
1066 assert_ne!(
1067 v,
1068 CellValue::Err(err::NAME),
1069 "{} ({:?}) has no implementation",
1070 d.name,
1071 d.id
1072 );
1073 }
1074 }
1075
1076 fn num_of(f: u32, args: &[f64]) -> CellValue {
1077 let a: Vec<CellValue> = args.iter().map(|x| CellValue::num(*x)).collect();
1078 eval(FuncId(f), &a)
1079 }
1080
1081 #[test]
1082 fn errors_propagate_and_are_inspected() {
1083 let div0 = CellValue::Err(err::DIV0);
1084 assert_eq!(eval(FuncId(10), std::slice::from_ref(&div0)), div0);
1085 assert_eq!(
1086 eval(FuncId(50), std::slice::from_ref(&div0)),
1087 CellValue::Bool(true)
1088 );
1089 assert_eq!(
1090 eval(FuncId(51), &[CellValue::Err(err::NA)]),
1091 CellValue::Bool(false)
1092 );
1093 assert_eq!(
1094 eval(FuncId(52), &[CellValue::Err(err::NA)]),
1095 CellValue::Bool(true)
1096 );
1097 assert_eq!(
1098 eval(FuncId(55), std::slice::from_ref(&div0)),
1099 CellValue::num(2.0)
1100 );
1101 assert_eq!(
1102 eval(FuncId(55), &[CellValue::num(1.0)]),
1103 CellValue::Err(err::NA)
1104 );
1105 assert_eq!(eval(FuncId(53), &[]), CellValue::Err(err::NA));
1106 assert_eq!(
1107 eval(FuncId(54), &[CellValue::Text("#num!".into())]),
1108 CellValue::Err(err::NUM)
1109 );
1110 assert_eq!(num_of(14, &[-1.0]), CellValue::Err(err::NUM));
1111 assert_eq!(num_of(102, &[1000.0]), CellValue::Err(err::NUM), "overflow");
1112 assert_eq!(eval(FuncId(999), &[]), CellValue::Err(err::NAME));
1113 }
1114
1115 #[test]
1116 fn rounding_is_decimal_correct() {
1117 assert_eq!(num_of(11, &[2.5]), CellValue::num(3.0));
1118 assert_eq!(num_of(11, &[-2.5]), CellValue::num(-3.0));
1119 assert_eq!(num_of(11, &[2.675, 2.0]), CellValue::num(2.68));
1120 assert_eq!(num_of(11, &[1234.5, -2.0]), CellValue::num(1200.0));
1121 assert_eq!(num_of(200, &[-3.125, 1.0]), CellValue::num(-3.2));
1122 assert_eq!(num_of(201, &[3.999, 2.0]), CellValue::num(3.99));
1123 assert_eq!(num_of(12, &[0.3, 0.1]), CellValue::num(0.3));
1124 assert_eq!(num_of(12, &[-2.5, 2.0]), CellValue::num(-4.0));
1125 assert_eq!(num_of(12, &[2.5, -2.0]), CellValue::Err(err::NUM));
1126 assert_eq!(num_of(205, &[2.5, 1.0]), CellValue::num(3.0));
1127 assert_eq!(num_of(205, &[-2.5, -2.0]), CellValue::num(-4.0));
1128 assert_eq!(num_of(212, &[-1.0]), CellValue::num(-2.0));
1129 assert_eq!(num_of(213, &[2.0]), CellValue::num(3.0));
1130 assert_eq!(num_of(213, &[0.0]), CellValue::num(1.0));
1131 assert_eq!(num_of(211, &[10.0, 3.0]), CellValue::num(9.0));
1132 assert_eq!(num_of(202, &[123.456, 2.0]), CellValue::num(120.0));
1133 }
1134
1135 #[test]
1138 fn edge_cases() {
1139 let n = CellValue::num;
1140 let s = |x: &str| CellValue::Text(x.into());
1141 let b = CellValue::Bool;
1142 let e = CellValue::Err;
1143 let call = |f: u32, a: &[CellValue]| eval(FuncId(f), a);
1144 assert_eq!(call(10, &[b(true)]), n(1.0));
1146 assert_eq!(call(10, &[CellValue::Date(5)]), n(5.0));
1147 assert_eq!(call(22, &[n(1.0), e(err::NA), e(err::DIV0)]), e(err::NA));
1148 assert_eq!(call(10, &[s("x")]), e(err::VALUE));
1149 assert_eq!(call(38, &[n(1.0), n(1.0), n(2.0)]), b(true));
1151 assert_eq!(call(38, &[n(1.0), n(1.0), n(2.0), b(false)]), b(false));
1152 assert_eq!(call(38, &[n(1.5), n(1.0), n(2.0), b(false)]), b(true));
1153 assert_eq!(call(51, &[n(1.0)]), b(false));
1154 assert_eq!(call(55, &[e(0)]), e(err::NA));
1155 assert_eq!(call(54, &[s("#bogus")]), e(err::VALUE));
1156 assert_eq!(call(106, &[n(8.0), n(1.0)]), e(err::DIV0));
1158 assert_eq!(call(106, &[n(8.0), n(2.0)]), n(3.0));
1159 assert_eq!(call(110, &[n(5.0), n(0.0)]), e(err::DIV0));
1160 assert_eq!(call(110, &[n(-5.0), n(3.0)]), n(1.0));
1161 assert_eq!(call(111, &[n(5.0), n(0.0)]), e(err::DIV0));
1162 assert_eq!(call(121, &[n(0.0), n(0.0)]), e(err::DIV0));
1163 assert_eq!(call(130, &[n(0.0)]), e(err::DIV0));
1164 assert_eq!(call(128, &[n(2e8)]), e(err::NUM));
1165 assert_eq!(call(138, &[n(0.5)]), e(err::NUM));
1166 assert_eq!(call(139, &[n(0.0)]), e(err::NUM));
1167 assert_eq!(call(136, &[n(0.5)]), n(1.0));
1168 assert_eq!(call(136, &[n(1.5)]), n(-1.0));
1169 assert_eq!(call(136, &[n(2.0)]), n(0.0));
1170 assert_eq!(call(137, &[n(1.0)]), n(-1.0));
1171 assert_eq!(call(137, &[n(2.0)]), n(1.0));
1172 assert_eq!(call(137, &[n(1.5)]), n(0.0));
1173 assert_eq!(call(142, &[n(1.0)]), n(1.0));
1175 assert_eq!(call(142, &[n(-1.0)]), e(err::NUM));
1176 assert_eq!(call(143, &[n(2.0), n(3.0)]), e(err::NUM));
1177 assert_eq!(call(144, &[n(0.0), n(0.0)]), n(1.0));
1178 assert_eq!(call(144, &[n(0.0), n(2.0)]), e(err::NUM));
1179 assert_eq!(call(145, &[n(2.0), n(3.0)]), e(err::NUM));
1180 assert_eq!(call(148, &[n(4.0), n(0.0)]), n(0.0));
1181 assert_eq!(call(148, &[n(4.0), n(6.0)]), n(12.0));
1182 assert_eq!(call(141, &[n(-1.0)]), e(err::NUM));
1183 assert_eq!(call(151, &[n(2.0), n(0.0)]), n(0.0));
1184 assert_eq!(call(151, &[n(-2.0)]), e(err::VALUE));
1185 assert_eq!(call(202, &[n(0.0), n(3.0)]), n(0.0));
1187 assert_eq!(call(202, &[n(5.0), n(0.0)]), e(err::NUM));
1188 assert_eq!(call(12, &[n(0.0), n(0.0)]), n(0.0));
1189 assert_eq!(call(12, &[n(3.0), n(0.0)]), e(err::DIV0));
1190 assert_eq!(call(205, &[n(3.0), n(0.0)]), n(0.0));
1191 assert_eq!(call(205, &[n(3.0), n(-1.0)]), e(err::NUM));
1192 assert_eq!(call(206, &[n(-5.5), n(2.0), n(1.0)]), n(-4.0));
1193 assert_eq!(call(206, &[n(-5.5), n(2.0)]), n(-6.0));
1194 assert_eq!(call(206, &[n(5.0), n(0.0)]), n(0.0));
1195 assert_eq!(call(207, &[n(-5.5), n(2.0), n(1.0)]), n(-6.0));
1196 assert_eq!(call(207, &[n(5.0), n(0.0)]), n(0.0));
1197 assert_eq!(call(208, &[n(5.0), n(0.0)]), n(0.0));
1198 assert_eq!(call(209, &[n(5.0), n(0.0)]), n(0.0));
1199 assert_eq!(call(211, &[n(5.0), n(0.0)]), n(0.0));
1200 assert_eq!(call(211, &[n(5.0), n(-2.0)]), e(err::NUM));
1201 assert_eq!(call(211, &[n(-5.0), n(-2.0)]), n(-6.0));
1202 assert_eq!(call(213, &[n(-2.0)]), n(-3.0));
1203 assert_eq!(call(213, &[n(3.0)]), n(3.0));
1204 assert_eq!(call(300, &[n(0.0)]), e(err::VALUE));
1206 assert_eq!(call(300, &[n(65.0)]), s("A"));
1207 assert_eq!(call(301, &[n(0.0)]), e(err::VALUE));
1208 assert_eq!(
1209 call(301, &[n(55_296.0)]),
1210 e(err::VALUE),
1211 "a surrogate is no char"
1212 );
1213 assert_eq!(call(302, &[s("")]), e(err::VALUE));
1214 assert_eq!(call(308, &[s("a"), s("abc"), n(0.0)]), e(err::VALUE));
1215 assert_eq!(call(308, &[s("a"), s("abc"), n(5.0)]), e(err::VALUE));
1216 assert_eq!(call(308, &[s(""), s("abc"), n(2.0)]), n(2.0));
1217 assert_eq!(call(308, &[s("abcd"), s("abc")]), e(err::VALUE));
1218 assert_eq!(call(310, &[s("abc"), n(-1.0)]), e(err::VALUE));
1219 assert_eq!(call(311, &[s("abc"), n(9.0)]), s("abc"));
1220 assert_eq!(call(312, &[s("abc"), n(0.0), n(1.0)]), e(err::VALUE));
1221 assert_eq!(call(312, &[s("abc"), n(9.0), n(1.0)]), s(""));
1222 assert_eq!(
1223 call(317, &[s("abc"), n(0.0), n(1.0), s("x")]),
1224 e(err::VALUE)
1225 );
1226 assert_eq!(call(317, &[s("abc"), n(2.0), n(1.0), s("XY")]), s("aXYc"));
1227 assert_eq!(call(318, &[s("ab"), n(-1.0)]), e(err::VALUE));
1228 assert_eq!(call(318, &[s("ab"), n(20_000.0)]), e(err::VALUE));
1229 assert_eq!(call(319, &[s("abc"), s(""), s("x")]), s("abc"));
1230 assert_eq!(
1231 call(319, &[s("abc"), s("b"), s("x"), n(0.0)]),
1232 e(err::VALUE)
1233 );
1234 assert_eq!(call(319, &[s("abc"), s("b"), s("x"), n(5.0)]), s("abc"));
1235 assert_eq!(call(321, &[s("")]), e(err::VALUE));
1236 assert_eq!(call(321, &[s("1,234")]), n(1234.0));
1237 assert_eq!(call(324, &[s("abc"), s("["), s("]")]), e(err::NA));
1238 assert_eq!(call(325, &[s("abc"), s("")]), e(err::VALUE));
1239 assert_eq!(call(309, &[s("x"), s("İx")]), n(2.0));
1241 assert_eq!(call(309, &[s("~*"), s("a*b")]), n(2.0));
1242 assert_eq!(call(309, &[s("~"), s("a~b")]), n(2.0));
1243 assert_eq!(call(309, &[s("a*c"), s("xabbc")]), n(2.0));
1244 assert_eq!(call(309, &[s("a*z"), s("abc")]), e(err::VALUE));
1245 assert_eq!(call(322, &[s("a-b"), s("-"), n(0.0)]), e(err::VALUE));
1248 assert_eq!(call(322, &[s("a-b"), s(""), n(1.0)]), s(""));
1249 assert_eq!(call(323, &[s("aXb"), s("x"), n(1.0), n(1.0)]), s("b"));
1250 assert_eq!(
1251 call(323, &[s("a-b"), s("-"), n(2.0), n(0.0), n(1.0)]),
1252 s("")
1253 );
1254 assert_eq!(
1255 call(322, &[s("a-b"), s("-"), n(-2.0), n(0.0), n(1.0)]),
1256 s("")
1257 );
1258 assert_eq!(
1259 call(322, &[s("ab"), s("-"), n(1.0), n(0.0), n(0.0), s("none")]),
1260 s("none")
1261 );
1262 assert_eq!(call(322, &[s("a-b-c"), s("-"), n(-5.0)]), e(err::NA));
1263 assert_eq!(call(322, &[s("a-b"), s("-"), n(-9.0)]), e(err::VALUE));
1264 assert_eq!(power(0.0, -1.0), Err(err::DIV0));
1266 assert_eq!(power(-8.0, 1.0 / 3.0), Err(err::NUM));
1267 assert_eq!(power(-2.0, 3.0), Ok(n(-8.0)));
1268 }
1269
1270 #[test]
1273 fn serial_dates_and_date_arithmetic() {
1274 let ms = |y, m, dd| {
1275 chrono::NaiveDate::from_ymd_opt(y, m, dd)
1276 .unwrap()
1277 .and_hms_opt(0, 0, 0)
1278 .unwrap()
1279 .and_utc()
1280 .timestamp_millis()
1281 };
1282 assert_eq!(d(&[CellValue::num(1.0)], 0), Ok(ms(1899, 12, 31)));
1283 assert_eq!(d(&[CellValue::num(61.0)], 0), Ok(ms(1900, 3, 1)));
1284 assert_eq!(d(&[CellValue::num(45658.0)], 0), Ok(ms(2025, 1, 1)));
1285 assert_eq!(
1286 d(&[CellValue::num(0.5)], 0),
1287 Ok(ms(1899, 12, 30) + DAY_MS / 2)
1288 );
1289 assert_eq!(d(&[CellValue::Date(7)], 0), Ok(7));
1290 assert_eq!(d(&[CellValue::Text("x".into())], 0), Err(err::VALUE));
1291 assert_eq!(d(&[CellValue::num(1e300)], 0), Err(err::NUM));
1292 assert_eq!(serial(ms(2025, 1, 1)), 45658.0);
1293 assert_eq!(
1294 date_plus_days(ms(2025, 1, 31), 1.0),
1295 CellValue::Date(ms(2025, 2, 1))
1296 );
1297 assert_eq!(date_plus_days(0, 1e30), CellValue::Err(err::NUM));
1298 assert_eq!(date_plus_days(i64::MAX - 1, 1.0), CellValue::Err(err::NUM));
1299 }
1300
1301 #[test]
1304 fn scalar_edges_against_libreoffice() {
1305 let (x, s) = (CellValue::num, |v: &str| CellValue::Text(v.into()));
1306 let e = CellValue::Err;
1307 let ev = |id: u32, a: &[CellValue]| eval(FuncId(id), a);
1308 assert_eq!(ev(38, &[x(5.0), x(1.0), x(3.0)]), CellValue::Bool(false));
1311 assert_eq!(ev(38, &[x(0.0), x(1.0), x(3.0)]), CellValue::Bool(false));
1312 assert_eq!(ev(51, &[e(err::NA)]), CellValue::Bool(false));
1313 assert_eq!(ev(51, &[e(err::DIV0)]), CellValue::Bool(true));
1314 assert_eq!(ev(100, &[x(-2.0)]), x(-1.0));
1315 assert_eq!(ev(100, &[x(0.0)]), x(0.0));
1316 assert_eq!(ev(121, &[x(0.0), x(1.0)]), x(std::f64::consts::FRAC_PI_2));
1318 assert_eq!(ev(127, &[x(-1.0)]), e(err::NUM));
1319 assert_eq!(ev(142, &[x(5.0)]), x(15.0));
1320 assert_eq!(ev(211, &[x(0.0), x(5.0)]), x(0.0));
1321 assert_eq!(ev(207, &[x(-2.5), x(1.0), x(0.0)]), x(-2.0));
1324 assert_eq!(ev(207, &[x(-2.5), x(1.0), x(1.0)]), x(-3.0));
1325 assert_eq!(ev(312, &[s("abc"), x(1.0), x(-1.0)]), e(err::VALUE));
1327 assert_eq!(ev(317, &[s("abc"), x(1.0), x(-1.0), s("x")]), e(err::VALUE));
1328 assert_eq!(round_to(1e20, 2.0, Dir::HalfAway), 1e20);
1330 assert_eq!(round_to(0.0, 2.0, Dir::HalfAway), 0.0);
1331 assert_eq!(sig15(f64::INFINITY), f64::INFINITY);
1332 assert_eq!(ev(309, &[s("a?"), s("a")]), e(err::VALUE));
1334 assert_eq!(d(&[x(f64::NAN)], 0), Err(err::NUM));
1336 assert_eq!(date_plus_days(0, f64::NAN), e(err::NUM));
1337 }
1338
1339 #[test]
1340 fn text_positions_are_characters() {
1341 let s = |x: &str| CellValue::Text(x.into());
1342 assert_eq!(eval(FuncId(313), &[s("héllo")]), CellValue::num(5.0));
1343 assert_eq!(
1344 eval(
1345 FuncId(312),
1346 &[s("héllo"), CellValue::num(2.0), CellValue::num(2.0)]
1347 ),
1348 s("él")
1349 );
1350 assert_eq!(
1351 eval(FuncId(309), &[s("A*"), s("xxaBc"),]),
1352 CellValue::num(3.0)
1353 );
1354 assert_eq!(
1355 eval(FuncId(309), &[s("b?d"), s("abcd")]),
1356 CellValue::num(2.0)
1357 );
1358 assert_eq!(
1359 eval(FuncId(308), &[s("B"), s("abc")]),
1360 CellValue::Err(err::VALUE)
1361 );
1362 assert_eq!(
1363 eval(FuncId(322), &[s("a-b-c"), s("-"), CellValue::num(-1.0)]),
1364 s("a-b")
1365 );
1366 assert_eq!(eval(FuncId(323), &[s("a-b-c"), s("-")]), s("b-c"));
1367 assert_eq!(
1368 eval(FuncId(323), &[s("abc"), s("-")]),
1369 CellValue::Err(err::NA)
1370 );
1371 assert_eq!(
1372 eval(
1373 FuncId(319),
1374 &[s("aaa"), s("a"), s("b"), CellValue::num(2.0)]
1375 ),
1376 s("aba")
1377 );
1378 assert_eq!(eval(FuncId(320), &[s(" a b ")]), s("a b"));
1379 assert_eq!(eval(FuncId(316), &[s("hello wORLD")]), s("Hello World"));
1380 assert_eq!(eval(FuncId(321), &[s(" 12.5% ")]), CellValue::num(0.125));
1381 assert_eq!(
1382 eval(
1383 FuncId(305),
1384 &[s("a"), CellValue::num(1.5), CellValue::Bool(true)]
1385 ),
1386 s("a1.5TRUE")
1387 );
1388 }
1389
1390 #[test]
1394 fn huge_counts_overflow_promptly() {
1395 let n = CellValue::num;
1396 let num_err = CellValue::Err(err::NUM);
1397 let t0 = std::time::Instant::now();
1398 assert_eq!(eval(FuncId(141), &[n(1e14)]), num_err, "FACT");
1399 assert_eq!(eval(FuncId(142), &[n(1.02e14)]), num_err, "FACTDOUBLE");
1400 assert_eq!(eval(FuncId(142), &[n(1e300)]), num_err, "FACTDOUBLE");
1401 assert_eq!(eval(FuncId(143), &[n(1e14), n(1e13)]), num_err, "COMBIN");
1402 assert_eq!(eval(FuncId(144), &[n(1e13), n(1e13)]), num_err, "COMBINA");
1403 assert_eq!(eval(FuncId(145), &[n(1e14), n(1e13)]), num_err, "PERMUT");
1404 assert_eq!(
1405 eval(FuncId(149), &[n(1.2e13), n(52.0), n(642.0)]),
1406 num_err,
1407 "MULTINOMIAL"
1408 );
1409 assert!(t0.elapsed() < std::time::Duration::from_secs(10));
1410 assert_eq!(eval(FuncId(141), &[n(5.0)]), n(120.0));
1412 assert_eq!(eval(FuncId(142), &[n(7.0)]), n(105.0));
1413 assert_eq!(eval(FuncId(142), &[n(8.0)]), n(384.0));
1414 assert_eq!(eval(FuncId(142), &[n(0.0)]), n(1.0));
1415 assert_eq!(eval(FuncId(143), &[n(10.0), n(3.0)]), n(120.0));
1416 assert_eq!(eval(FuncId(143), &[n(1e14), n(1.0)]), n(1e14));
1417 assert_eq!(eval(FuncId(145), &[n(10.0), n(3.0)]), n(720.0));
1418 assert_eq!(eval(FuncId(149), &[n(2.0), n(3.0), n(4.0)]), n(1260.0));
1419 assert_eq!(eval(FuncId(149), &[n(0.0), n(0.0)]), n(1.0));
1420 }
1421
1422 #[test]
1428 fn floor_and_ceiling_snap_to_15_digits() {
1429 let x = 9_618_236.874_990_381;
1430 assert_eq!(num_of(12, &[x, 0.625]), CellValue::num(9_618_236.25));
1431 assert_eq!(num_of(205, &[x, 0.625]), CellValue::num(9_618_236.875));
1432 assert_eq!(num_of(208, &[x, 0.625]), CellValue::num(9_618_236.25));
1433 assert_eq!(
1434 num_of(205, &[1.168_724_262_385_476_7e-10, 117.0]),
1435 CellValue::num(117.0)
1436 );
1437 assert_eq!(num_of(205, &[1e-13, 1.0]), CellValue::num(1.0));
1438 assert_eq!(num_of(12, &[1e-13, 1.0]), CellValue::num(0.0));
1439 assert_eq!(num_of(12, &[-1e-13, 1.0]), CellValue::num(-1.0));
1440 assert_eq!(num_of(207, &[1e-13, 1.0]), CellValue::num(1.0));
1441 assert_eq!(num_of(207, &[-1e-13, 1.0, 1.0]), CellValue::num(-1.0));
1442 assert_eq!(num_of(206, &[1e-13, 1.0]), CellValue::num(0.0));
1443 assert_eq!(num_of(205, &[0.0, 1.0]), CellValue::num(0.0));
1444 assert_eq!(num_of(12, &[0.3, 0.1]), CellValue::num(0.3));
1446 assert_eq!(num_of(205, &[0.3, 0.1]), CellValue::num(0.3));
1447 }
1448}