kcl_lib/std/
math.rs

1//! Functions related to mathematics.
2
3use anyhow::Result;
4use kcl_derive_docs::stdlib;
5
6use super::args::FromArgs;
7use crate::{
8    errors::{KclError, KclErrorDetails},
9    execution::{ExecState, KclValue},
10    std::args::{Args, TyF64},
11};
12
13/// Compute the remainder after dividing `num` by `div`.
14/// If `num` is negative, the result will be too.
15pub async fn rem(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
16    let n = args.get_unlabeled_kw_arg("number to divide")?;
17    let d = args.get_kw_arg("divisor")?;
18    let remainder = inner_rem(n, d);
19
20    Ok(args.make_user_val_from_f64(remainder))
21}
22
23/// Compute the remainder after dividing `num` by `div`.
24/// If `num` is negative, the result will be too.
25///
26/// ```no_run
27/// assertEqual(rem( 7,  divisor =  4),  3, 0.01, "remainder is 3" )
28/// assertEqual(rem(-7,  divisor =  4), -3, 0.01, "remainder is -3")
29/// assertEqual(rem( 7,  divisor = -4),  3, 0.01, "remainder is 3" )
30/// assertEqual(rem( 6,    divisor = 2.5), 1,   0.01, "remainder is 1" )
31/// assertEqual(rem( 6.5,  divisor = 2.5), 1.5, 0.01, "remainder is 1.5" )
32/// assertEqual(rem( 6.5,  divisor = 2),   0.5, 0.01, "remainder is 0.5" )
33/// ```
34#[stdlib {
35    name = "rem",
36    tags = ["math"],
37    keywords = true,
38    unlabeled_first = true,
39    args = {
40        num = {docs = "The number which will be divided by `divisor`."},
41        divisor = {docs = "The number which will divide `num`."},
42    }
43}]
44fn inner_rem(num: f64, divisor: f64) -> f64 {
45    num % divisor
46}
47
48/// Compute the cosine of a number (in radians).
49pub async fn cos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
50    let num = args.get_number()?;
51    Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.cos())))
52}
53
54/// Compute the sine of a number (in radians).
55pub async fn sin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
56    let num = args.get_number()?;
57    Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.sin())))
58}
59
60/// Compute the tangent of a number (in radians).
61pub async fn tan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
62    let num = args.get_number()?;
63    Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.tan())))
64}
65
66/// Return the value of `pi`. Archimedes’ constant (π).
67pub async fn pi(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
68    let result = inner_pi()?;
69
70    Ok(args.make_user_val_from_f64(result))
71}
72
73/// Return the value of `pi`. Archimedes’ constant (π).
74///
75/// **DEPRECATED** use the constant PI
76///
77/// ```no_run
78/// circumference = 70
79///
80/// exampleSketch = startSketchOn("XZ")
81///  |> circle( center = [0, 0], radius = circumference/ (2 * pi()) )
82///
83/// example = extrude(exampleSketch, length = 5)
84/// ```
85#[stdlib {
86    name = "pi",
87    tags = ["math"],
88    deprecated = true,
89}]
90fn inner_pi() -> Result<f64, KclError> {
91    Ok(std::f64::consts::PI)
92}
93
94/// Compute the square root of a number.
95pub async fn sqrt(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
96    let num = args.get_number()?;
97    let result = inner_sqrt(num)?;
98
99    Ok(args.make_user_val_from_f64(result))
100}
101
102/// Compute the square root of a number.
103///
104/// ```no_run
105/// exampleSketch = startSketchOn("XZ")
106///   |> startProfileAt([0, 0], %)
107///   |> angledLine({
108///     angle = 50,
109///     length = sqrt(2500),
110///   }, %)
111///   |> yLine(endAbsolute = 0)
112///   |> close()
113///
114/// example = extrude(exampleSketch, length = 5)
115/// ```
116#[stdlib {
117    name = "sqrt",
118    tags = ["math"],
119}]
120fn inner_sqrt(num: f64) -> Result<f64, KclError> {
121    Ok(num.sqrt())
122}
123
124/// Compute the absolute value of a number.
125pub async fn abs(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
126    let num = args.get_number()?;
127    let result = inner_abs(num)?;
128
129    Ok(args.make_user_val_from_f64(result))
130}
131
132/// Compute the absolute value of a number.
133///
134/// ```no_run
135/// myAngle = -120
136///
137/// sketch001 = startSketchOn('XZ')
138///   |> startProfileAt([0, 0], %)
139///   |> line(end = [8, 0])
140///   |> angledLine({
141///     angle = abs(myAngle),
142///     length = 5,
143///   }, %)
144///   |> line(end = [-5, 0])
145///   |> angledLine({
146///     angle = myAngle,
147///     length = 5,
148///   }, %)
149///   |> close()
150///
151/// baseExtrusion = extrude(sketch001, length = 5)
152/// ```
153#[stdlib {
154    name = "abs",
155    tags = ["math"],
156}]
157fn inner_abs(num: f64) -> Result<f64, KclError> {
158    Ok(num.abs())
159}
160
161/// Round a number to the nearest integer.
162pub async fn round(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
163    let num = args.get_number()?;
164    let result = inner_round(num)?;
165
166    Ok(args.make_user_val_from_f64(result))
167}
168
169/// Round a number to the nearest integer.
170///
171/// ```no_run
172/// sketch001 = startSketchOn('XZ')
173///    |> startProfileAt([0, 0], %)
174///    |> line(endAbsolute = [12, 10])
175///    |> line(end = [round(7.02986), 0])
176///    |> yLine(endAbsolute = 0)
177///    |> close()
178///
179/// extrude001 = extrude(sketch001, length = 5)
180/// ```
181#[stdlib {
182    name = "round",
183    tags = ["math"],
184}]
185fn inner_round(num: f64) -> Result<f64, KclError> {
186    Ok(num.round())
187}
188
189/// Compute the largest integer less than or equal to a number.
190pub async fn floor(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
191    let num = args.get_number()?;
192    let result = inner_floor(num)?;
193
194    Ok(args.make_user_val_from_f64(result))
195}
196
197/// Compute the largest integer less than or equal to a number.
198///
199/// ```no_run
200/// sketch001 = startSketchOn('XZ')
201///    |> startProfileAt([0, 0], %)
202///    |> line(endAbsolute = [12, 10])
203///    |> line(end = [floor(7.02986), 0])
204///    |> yLine(endAbsolute = 0)
205///    |> close()
206///
207/// extrude001 = extrude(sketch001, length = 5)
208/// ```
209#[stdlib {
210    name = "floor",
211    tags = ["math"],
212}]
213fn inner_floor(num: f64) -> Result<f64, KclError> {
214    Ok(num.floor())
215}
216
217/// Compute the smallest integer greater than or equal to a number.
218pub async fn ceil(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
219    let num = args.get_number()?;
220    let result = inner_ceil(num)?;
221
222    Ok(args.make_user_val_from_f64(result))
223}
224
225/// Compute the smallest integer greater than or equal to a number.
226///
227/// ```no_run
228/// sketch001 = startSketchOn('XZ')
229///   |> startProfileAt([0, 0], %)
230///   |> line(endAbsolute = [12, 10])
231///   |> line(end = [ceil(7.02986), 0])
232///   |> yLine(endAbsolute = 0)
233///   |> close()
234///
235/// extrude001 = extrude(sketch001, length = 5)
236/// ```
237#[stdlib {
238    name = "ceil",
239    tags = ["math"],
240}]
241fn inner_ceil(num: f64) -> Result<f64, KclError> {
242    Ok(num.ceil())
243}
244
245/// Compute the minimum of the given arguments.
246pub async fn min(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
247    let nums = args.get_number_array()?;
248    let result = inner_min(nums);
249
250    Ok(args.make_user_val_from_f64(result))
251}
252
253/// Compute the minimum of the given arguments.
254///
255/// ```no_run
256/// exampleSketch = startSketchOn("XZ")
257///   |> startProfileAt([0, 0], %)
258///   |> angledLine({
259///     angle = 70,
260///     length = min(15, 31, 4, 13, 22)
261///   }, %)
262///   |> line(end = [20, 0])
263///   |> close()
264///
265/// example = extrude(exampleSketch, length = 5)
266/// ```
267#[stdlib {
268    name = "min",
269    tags = ["math"],
270}]
271fn inner_min(args: Vec<f64>) -> f64 {
272    let mut min = f64::MAX;
273    for arg in args.iter() {
274        if *arg < min {
275            min = *arg;
276        }
277    }
278
279    min
280}
281
282/// Compute the maximum of the given arguments.
283pub async fn max(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
284    let nums = args.get_number_array()?;
285    let result = inner_max(nums);
286
287    Ok(args.make_user_val_from_f64(result))
288}
289
290/// Compute the maximum of the given arguments.
291///
292/// ```no_run
293/// exampleSketch = startSketchOn("XZ")
294///   |> startProfileAt([0, 0], %)
295///   |> angledLine({
296///     angle = 70,
297///     length = max(15, 31, 4, 13, 22)
298///   }, %)
299///   |> line(end = [20, 0])
300///   |> close()
301///
302/// example = extrude(exampleSketch, length = 5)
303/// ```
304#[stdlib {
305    name = "max",
306    tags = ["math"],
307}]
308fn inner_max(args: Vec<f64>) -> f64 {
309    let mut max = f64::MIN;
310    for arg in args.iter() {
311        if *arg > max {
312            max = *arg;
313        }
314    }
315
316    max
317}
318
319/// Compute the number to a power.
320pub async fn pow(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
321    let nums = args.get_number_array()?;
322    if nums.len() > 2 {
323        return Err(KclError::Type(KclErrorDetails {
324            message: format!("expected 2 arguments, got {}", nums.len()),
325            source_ranges: vec![args.source_range],
326        }));
327    }
328
329    if nums.len() <= 1 {
330        return Err(KclError::Type(KclErrorDetails {
331            message: format!("expected 2 arguments, got {}", nums.len()),
332            source_ranges: vec![args.source_range],
333        }));
334    }
335
336    let result = inner_pow(nums[0], nums[1])?;
337
338    Ok(args.make_user_val_from_f64(result))
339}
340
341/// Compute the number to a power.
342///
343/// ```no_run
344/// exampleSketch = startSketchOn("XZ")
345///   |> startProfileAt([0, 0], %)
346///   |> angledLine({
347///     angle = 50,
348///     length = pow(5, 2),
349///   }, %)
350///   |> yLine(endAbsolute = 0)
351///   |> close()
352///
353/// example = extrude(exampleSketch, length = 5)
354/// ```
355#[stdlib {
356    name = "pow",
357    tags = ["math"],
358}]
359fn inner_pow(num: f64, pow: f64) -> Result<f64, KclError> {
360    Ok(num.powf(pow))
361}
362
363/// Compute the arccosine of a number (in radians).
364pub async fn acos(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
365    let num = args.get_number()?;
366    let result = inner_acos(num)?;
367
368    Ok(args.make_user_val_from_f64(result))
369}
370
371/// Compute the arccosine of a number (in radians).
372///
373/// ```no_run
374/// sketch001 = startSketchOn('XZ')
375///   |> startProfileAt([0, 0], %)
376///   |> angledLine({
377///     angle = toDegrees(acos(0.5)),
378///     length = 10,
379///   }, %)
380///   |> line(end = [5, 0])
381///   |> line(endAbsolute = [12, 0])
382///   |> close()
383///
384/// extrude001 = extrude(sketch001, length = 5)
385/// ```
386#[stdlib {
387    name = "acos",
388    tags = ["math"],
389}]
390fn inner_acos(num: f64) -> Result<f64, KclError> {
391    Ok(num.acos())
392}
393
394/// Compute the arcsine of a number (in radians).
395pub async fn asin(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
396    let num = args.get_number()?;
397    let result = inner_asin(num)?;
398
399    Ok(args.make_user_val_from_f64(result))
400}
401
402/// Compute the arcsine of a number (in radians).
403///
404/// ```no_run
405/// sketch001 = startSketchOn('XZ')
406///   |> startProfileAt([0, 0], %)
407///   |> angledLine({
408///     angle = toDegrees(asin(0.5)),
409///     length = 20,
410///   }, %)
411///   |> yLine(endAbsolute = 0)
412///   |> close()
413///
414/// extrude001 = extrude(sketch001, length = 5)
415/// ```
416#[stdlib {
417    name = "asin",
418    tags = ["math"],
419}]
420fn inner_asin(num: f64) -> Result<f64, KclError> {
421    Ok(num.asin())
422}
423
424/// Compute the arctangent of a number (in radians).
425pub async fn atan(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
426    let num = args.get_number()?;
427    let result = inner_atan(num)?;
428
429    Ok(args.make_user_val_from_f64(result))
430}
431
432/// Compute the arctangent of a number (in radians).
433///
434/// ```no_run
435/// sketch001 = startSketchOn('XZ')
436///   |> startProfileAt([0, 0], %)
437///   |> angledLine({
438///     angle = toDegrees(atan(1.25)),
439///     length = 20,
440///   }, %)
441///   |> yLine(endAbsolute = 0)
442///   |> close()
443///
444/// extrude001 = extrude(sketch001, length = 5)
445/// ```
446#[stdlib {
447    name = "atan",
448    tags = ["math"],
449}]
450fn inner_atan(num: f64) -> Result<f64, KclError> {
451    Ok(num.atan())
452}
453
454/// Compute the four quadrant arctangent of Y and X (in radians).
455pub async fn atan2(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
456    let (y, x) = FromArgs::from_args(&args, 0)?;
457    let result = inner_atan2(y, x)?;
458
459    Ok(args.make_user_val_from_f64(result))
460}
461
462/// Compute the four quadrant arctangent of Y and X (in radians).
463///
464/// ```no_run
465/// sketch001 = startSketchOn('XZ')
466///   |> startProfileAt([0, 0], %)
467///   |> angledLine({
468///     angle = toDegrees(atan2(1.25, 2)),
469///     length = 20,
470///   }, %)
471///   |> yLine(endAbsolute = 0)
472///   |> close()
473///
474/// extrude001 = extrude(sketch001, length = 5)
475/// ```
476#[stdlib {
477    name = "atan2",
478    tags = ["math"],
479}]
480fn inner_atan2(y: f64, x: f64) -> Result<f64, KclError> {
481    Ok(y.atan2(x))
482}
483
484/// Compute the logarithm of the number with respect to an arbitrary base.
485///
486/// The result might not be correctly rounded owing to implementation
487/// details; `log2()` can produce more accurate results for base 2,
488/// and `log10()` can produce more accurate results for base 10.
489pub async fn log(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
490    let nums = args.get_number_array()?;
491    if nums.len() > 2 {
492        return Err(KclError::Type(KclErrorDetails {
493            message: format!("expected 2 arguments, got {}", nums.len()),
494            source_ranges: vec![args.source_range],
495        }));
496    }
497
498    if nums.len() <= 1 {
499        return Err(KclError::Type(KclErrorDetails {
500            message: format!("expected 2 arguments, got {}", nums.len()),
501            source_ranges: vec![args.source_range],
502        }));
503    }
504    let result = inner_log(nums[0], nums[1])?;
505
506    Ok(args.make_user_val_from_f64(result))
507}
508
509/// Compute the logarithm of the number with respect to an arbitrary base.
510///
511/// The result might not be correctly rounded owing to implementation
512/// details; `log2()` can produce more accurate results for base 2,
513/// and `log10()` can produce more accurate results for base 10.
514///
515/// ```no_run
516/// exampleSketch = startSketchOn("XZ")
517///   |> startProfileAt([0, 0], %)
518///   |> line(end = [log(100, 5), 0])
519///   |> line(end = [5, 8])
520///   |> line(end = [-10, 0])
521///   |> close()
522///
523/// example = extrude(exampleSketch, length = 5)
524/// ```
525#[stdlib {
526    name = "log",
527    tags = ["math"],
528}]
529fn inner_log(num: f64, base: f64) -> Result<f64, KclError> {
530    Ok(num.log(base))
531}
532
533/// Compute the base 2 logarithm of the number.
534pub async fn log2(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
535    let num = args.get_number()?;
536    let result = inner_log2(num)?;
537
538    Ok(args.make_user_val_from_f64(result))
539}
540
541/// Compute the base 2 logarithm of the number.
542///
543/// ```no_run
544/// exampleSketch = startSketchOn("XZ")
545///   |> startProfileAt([0, 0], %)
546///   |> line(end = [log2(100), 0])
547///   |> line(end = [5, 8])
548///   |> line(end = [-10, 0])
549///   |> close()
550///
551/// example = extrude(exampleSketch, length = 5)
552/// ```
553#[stdlib {
554    name = "log2",
555    tags = ["math"],
556}]
557fn inner_log2(num: f64) -> Result<f64, KclError> {
558    Ok(num.log2())
559}
560
561/// Compute the base 10 logarithm of the number.
562pub async fn log10(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
563    let num = args.get_number()?;
564    let result = inner_log10(num)?;
565
566    Ok(args.make_user_val_from_f64(result))
567}
568
569/// Compute the base 10 logarithm of the number.
570///
571/// ```no_run
572/// exampleSketch = startSketchOn("XZ")
573///   |> startProfileAt([0, 0], %)
574///   |> line(end = [log10(100), 0])
575///   |> line(end = [5, 8])
576///   |> line(end = [-10, 0])
577///   |> close()
578///
579/// example = extrude(exampleSketch, length = 5)
580/// ```
581#[stdlib {
582    name = "log10",
583    tags = ["math"],
584}]
585fn inner_log10(num: f64) -> Result<f64, KclError> {
586    Ok(num.log10())
587}
588
589/// Compute the natural logarithm of the number.
590pub async fn ln(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
591    let num = args.get_number()?;
592    let result = inner_ln(num)?;
593
594    Ok(args.make_user_val_from_f64(result))
595}
596
597/// Compute the natural logarithm of the number.
598///
599/// ```no_run
600/// exampleSketch = startSketchOn("XZ")
601///   |> startProfileAt([0, 0], %)
602///   |> line(end = [ln(100), 15])
603///   |> line(end = [5, -6])
604///   |> line(end = [-10, -10])
605///   |> close()
606///
607/// example = extrude(exampleSketch, length = 5)
608/// ```
609#[stdlib {
610    name = "ln",
611    tags = ["math"],
612}]
613fn inner_ln(num: f64) -> Result<f64, KclError> {
614    Ok(num.ln())
615}
616
617/// Return the value of Euler’s number `e`.
618pub async fn e(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
619    let result = inner_e()?;
620
621    Ok(args.make_user_val_from_f64(result))
622}
623
624/// Return the value of Euler’s number `e`.
625///
626/// **DEPRECATED** use the constant E
627///
628/// ```no_run
629/// exampleSketch = startSketchOn("XZ")
630///   |> startProfileAt([0, 0], %)
631///   |> angledLine({
632///     angle = 30,
633///     length = 2 * e() ^ 2,
634///   }, %)
635///   |> yLine(endAbsolute = 0)
636///   |> close()
637///  
638/// example = extrude(exampleSketch, length = 10)
639/// ```
640#[stdlib {
641    name = "e",
642    tags = ["math"],
643    deprecated = true,
644}]
645fn inner_e() -> Result<f64, KclError> {
646    Ok(std::f64::consts::E)
647}
648
649/// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
650pub async fn tau(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
651    let result = inner_tau()?;
652
653    Ok(args.make_user_val_from_f64(result))
654}
655
656/// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
657///
658/// **DEPRECATED** use the constant TAU
659///
660/// ```no_run
661/// exampleSketch = startSketchOn("XZ")
662///   |> startProfileAt([0, 0], %)
663///   |> angledLine({
664///     angle = 50,
665///     length = 10 * tau(),
666///   }, %)
667///   |> yLine(endAbsolute = 0)
668///   |> close()
669///
670/// example = extrude(exampleSketch, length = 5)
671/// ```
672#[stdlib {
673    name = "tau",
674    tags = ["math"],
675    deprecated = true,
676}]
677fn inner_tau() -> Result<f64, KclError> {
678    Ok(std::f64::consts::TAU)
679}
680
681/// Converts a number from degrees to radians.
682pub async fn to_radians(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
683    let num = args.get_number()?;
684    let result = inner_to_radians(num)?;
685
686    Ok(args.make_user_val_from_f64(result))
687}
688
689/// Converts a number from degrees to radians.
690///
691/// ```no_run
692/// exampleSketch = startSketchOn("XZ")
693///   |> startProfileAt([0, 0], %)
694///   |> angledLine({
695///     angle = 50,
696///     length = 70 * cos(toRadians(45)),
697///   }, %)
698///   |> yLine(endAbsolute = 0)
699///   |> close()
700///
701/// example = extrude(exampleSketch, length = 5)
702/// ```
703#[stdlib {
704    name = "toRadians",
705    tags = ["math"],
706}]
707fn inner_to_radians(num: f64) -> Result<f64, KclError> {
708    Ok(num.to_radians())
709}
710
711/// Converts a number from radians to degrees.
712pub async fn to_degrees(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
713    let num = args.get_number()?;
714    let result = inner_to_degrees(num)?;
715
716    Ok(args.make_user_val_from_f64(result))
717}
718
719/// Converts a number from radians to degrees.
720///
721/// ```no_run
722/// exampleSketch = startSketchOn("XZ")
723///   |> startProfileAt([0, 0], %)
724///   |> angledLine({
725///     angle = 50,
726///     length = 70 * cos(toDegrees(pi()/4)),
727///   }, %)
728///   |> yLine(endAbsolute = 0)
729///   |> close()
730///
731/// example = extrude(exampleSketch, length = 5)
732/// ```
733#[stdlib {
734    name = "toDegrees",
735    tags = ["math"],
736}]
737fn inner_to_degrees(num: f64) -> Result<f64, KclError> {
738    Ok(num.to_degrees())
739}
740
741#[cfg(test)]
742mod tests {
743    use pretty_assertions::assert_eq;
744
745    use super::*;
746
747    #[test]
748    fn test_inner_max() {
749        let nums = vec![4.0, 5.0, 6.0];
750        let result = inner_max(nums);
751        assert_eq!(result, 6.0);
752    }
753
754    #[test]
755    fn test_inner_max_with_neg() {
756        let nums = vec![4.0, -5.0];
757        let result = inner_max(nums);
758        assert_eq!(result, 4.0);
759    }
760
761    #[test]
762    fn test_inner_min() {
763        let nums = vec![4.0, 5.0, 6.0];
764        let result = inner_min(nums);
765        assert_eq!(result, 4.0);
766    }
767
768    #[test]
769    fn test_inner_min_with_neg() {
770        let nums = vec![4.0, -5.0];
771        let result = inner_min(nums);
772        assert_eq!(result, -5.0);
773    }
774}