1use ferray_core::Array;
8use ferray_core::dimension::Dimension;
9use ferray_core::dtype::Element;
10use ferray_core::error::{FerrayError, FerrayResult};
11use num_traits::Float;
12
13use crate::helpers::{binary_elementwise_op, binary_mixed_op, unary_float_op, unary_map_op};
14
15pub fn isnan<T, D>(input: &Array<T, D>) -> FerrayResult<Array<bool, D>>
21where
22 T: Element + Float,
23 D: Dimension,
24{
25 unary_map_op(input, num_traits::Float::is_nan)
26}
27
28pub fn isinf<T, D>(input: &Array<T, D>) -> FerrayResult<Array<bool, D>>
30where
31 T: Element + Float,
32 D: Dimension,
33{
34 unary_map_op(input, num_traits::Float::is_infinite)
35}
36
37pub fn isfinite<T, D>(input: &Array<T, D>) -> FerrayResult<Array<bool, D>>
39where
40 T: Element + Float,
41 D: Dimension,
42{
43 unary_map_op(input, num_traits::Float::is_finite)
44}
45
46pub fn isneginf<T, D>(input: &Array<T, D>) -> FerrayResult<Array<bool, D>>
48where
49 T: Element + Float,
50 D: Dimension,
51{
52 unary_map_op(input, |x| x.is_infinite() && x < <T as Element>::zero())
53}
54
55pub fn isposinf<T, D>(input: &Array<T, D>) -> FerrayResult<Array<bool, D>>
57where
58 T: Element + Float,
59 D: Dimension,
60{
61 unary_map_op(input, |x| x.is_infinite() && x > <T as Element>::zero())
62}
63
64pub fn signbit<T, D>(input: &Array<T, D>) -> FerrayResult<Array<bool, D>>
66where
67 T: Element + Float,
68 D: Dimension,
69{
70 unary_map_op(input, num_traits::Float::is_sign_negative)
71}
72
73pub fn nan_to_num<T, D>(
81 input: &Array<T, D>,
82 nan: Option<T>,
83 posinf: Option<T>,
84 neginf: Option<T>,
85) -> FerrayResult<Array<T, D>>
86where
87 T: Element + Float,
88 D: Dimension,
89{
90 let nan_val = nan.unwrap_or_else(|| <T as Element>::zero());
91 let posinf_val = posinf.unwrap_or_else(T::max_value);
92 let neginf_val = neginf.unwrap_or_else(T::min_value);
93 unary_float_op(input, |x| {
94 if x.is_nan() {
95 nan_val
96 } else if x.is_infinite() {
97 if x > <T as Element>::zero() {
98 posinf_val
99 } else {
100 neginf_val
101 }
102 } else {
103 x
104 }
105 })
106}
107
108pub fn clip<T, D>(input: &Array<T, D>, a_min: T, a_max: T) -> FerrayResult<Array<T, D>>
110where
111 T: Element + Float,
112 D: Dimension,
113{
114 if a_min > a_max {
115 return Err(FerrayError::invalid_value("clip: a_min must be <= a_max"));
116 }
117 unary_float_op(input, |x| {
118 if x < a_min {
119 a_min
120 } else if x > a_max {
121 a_max
122 } else {
123 x
124 }
125 })
126}
127
128pub fn clip_ord<T, D>(input: &Array<T, D>, a_min: T, a_max: T) -> FerrayResult<Array<T, D>>
135where
136 T: Element + PartialOrd + Copy,
137 D: Dimension,
138{
139 if a_min > a_max {
140 return Err(FerrayError::invalid_value(
141 "clip_ord: a_min must be <= a_max",
142 ));
143 }
144 let data: Vec<T> = input
145 .iter()
146 .map(|&x| {
147 if x < a_min {
148 a_min
149 } else if x > a_max {
150 a_max
151 } else {
152 x
153 }
154 })
155 .collect();
156 Array::from_vec(input.dim().clone(), data)
157}
158
159#[inline]
165fn nextafter_f64(a: f64, b: f64) -> f64 {
166 if a.is_nan() || b.is_nan() {
167 return f64::NAN;
168 }
169 if a == b {
170 return b;
171 }
172 if a == 0.0 {
173 return if b > 0.0 {
175 f64::from_bits(1)
176 } else {
177 f64::from_bits(1u64 | (1u64 << 63))
178 };
179 }
180 let bits = a.to_bits();
181 let new_bits = if (a < b) == (a > 0.0) {
182 bits + 1
184 } else {
185 bits - 1
187 };
188 f64::from_bits(new_bits)
189}
190
191#[inline]
193fn nextafter_f32(a: f32, b: f32) -> f32 {
194 if a.is_nan() || b.is_nan() {
195 return f32::NAN;
196 }
197 if a == b {
198 return b;
199 }
200 if a == 0.0 {
201 return if b > 0.0 {
202 f32::from_bits(1)
203 } else {
204 f32::from_bits(1u32 | (1u32 << 31))
205 };
206 }
207 let bits = a.to_bits();
208 let new_bits = if (a < b) == (a > 0.0) {
209 bits + 1
210 } else {
211 bits - 1
212 };
213 f32::from_bits(new_bits)
214}
215
216pub fn nextafter<T, D>(x1: &Array<T, D>, x2: &Array<T, D>) -> FerrayResult<Array<T, D>>
218where
219 T: Element + Float,
220 D: Dimension,
221{
222 use std::any::TypeId;
223
224 if TypeId::of::<T>() == TypeId::of::<f64>() {
225 let a_f64 = unsafe { &*std::ptr::from_ref::<Array<T, D>>(x1).cast::<Array<f64, D>>() };
227 let b_f64 = unsafe { &*std::ptr::from_ref::<Array<T, D>>(x2).cast::<Array<f64, D>>() };
228 let result = binary_elementwise_op(a_f64, b_f64, nextafter_f64)?;
229 Ok(unsafe { crate::helpers::reinterpret_array::<f64, T, D>(result) })
230 } else if TypeId::of::<T>() == TypeId::of::<f32>() {
231 let a_f32 = unsafe { &*std::ptr::from_ref::<Array<T, D>>(x1).cast::<Array<f32, D>>() };
233 let b_f32 = unsafe { &*std::ptr::from_ref::<Array<T, D>>(x2).cast::<Array<f32, D>>() };
234 let result = binary_elementwise_op(a_f32, b_f32, nextafter_f32)?;
235 Ok(unsafe { crate::helpers::reinterpret_array::<f32, T, D>(result) })
236 } else {
237 binary_elementwise_op(x1, x2, |a, b| {
239 let a64 = a.to_f64().unwrap();
240 let b64 = b.to_f64().unwrap();
241 T::from(nextafter_f64(a64, b64)).unwrap()
242 })
243 }
244}
245
246#[inline]
248fn spacing_f64(x: f64) -> f64 {
249 if x.is_nan() || x.is_infinite() {
250 return f64::NAN;
251 }
252 let ax = x.abs();
253 if ax == 0.0 {
254 return f64::from_bits(1); }
256 nextafter_f64(ax, f64::INFINITY) - ax
257}
258
259#[inline]
261fn spacing_f32(x: f32) -> f32 {
262 if x.is_nan() || x.is_infinite() {
263 return f32::NAN;
264 }
265 let ax = x.abs();
266 if ax == 0.0 {
267 return f32::from_bits(1); }
269 nextafter_f32(ax, f32::INFINITY) - ax
270}
271
272pub fn spacing<T, D>(input: &Array<T, D>) -> FerrayResult<Array<T, D>>
275where
276 T: Element + Float,
277 D: Dimension,
278{
279 use std::any::TypeId;
280
281 if TypeId::of::<T>() == TypeId::of::<f64>() {
282 let f64_input =
283 unsafe { &*std::ptr::from_ref::<Array<T, D>>(input).cast::<Array<f64, D>>() };
284 let result = unary_float_op(f64_input, spacing_f64)?;
285 Ok(unsafe { crate::helpers::reinterpret_array::<f64, T, D>(result) })
286 } else if TypeId::of::<T>() == TypeId::of::<f32>() {
287 let f32_input =
288 unsafe { &*std::ptr::from_ref::<Array<T, D>>(input).cast::<Array<f32, D>>() };
289 let result = unary_float_op(f32_input, spacing_f32)?;
290 Ok(unsafe { crate::helpers::reinterpret_array::<f32, T, D>(result) })
291 } else {
292 unary_float_op(input, |x| {
294 let x64 = x.to_f64().unwrap();
295 T::from(spacing_f64(x64)).unwrap()
296 })
297 }
298}
299
300pub fn ldexp<T, D>(x: &Array<T, D>, n: &Array<i32, D>) -> FerrayResult<Array<T, D>>
304where
305 T: Element + Float,
306 D: Dimension,
307{
308 let two = <T as Element>::one() + <T as Element>::one();
309 binary_mixed_op(x, n, move |xi, ni| xi * two.powi(ni))
310}
311
312#[inline]
316fn frexp_f64(x: f64) -> (f64, i32) {
317 if x == 0.0 || x.is_nan() || x.is_infinite() {
318 return (x, 0);
319 }
320 let bits = x.to_bits();
321 let sign = bits & (1u64 << 63);
322 let mut exp = ((bits >> 52) & 0x7FF) as i32;
323 if exp == 0 {
324 let nx = x * (1u64 << 63) as f64 * 2.0;
326 let nbits = nx.to_bits();
327 exp = ((nbits >> 52) & 0x7FF) as i32 - 64;
328 let frac = f64::from_bits((nbits & !(0x7FFu64 << 52)) | (0x3FEu64 << 52));
329 return (if sign != 0 { -frac.abs() } else { frac }, exp - 0x3FE);
330 }
331 let frac = f64::from_bits((bits & !(0x7FFu64 << 52)) | (0x3FEu64 << 52));
333 (frac, exp - 0x3FE)
335}
336
337#[inline]
341fn frexp_f32(x: f32) -> (f32, i32) {
342 if x == 0.0 || x.is_nan() || x.is_infinite() {
343 return (x, 0);
344 }
345 let bits = x.to_bits();
346 let sign = bits & (1u32 << 31);
347 let mut exp = ((bits >> 23) & 0xFF) as i32;
348 if exp == 0 {
349 let nx = x * (1u32 << 31) as f32 * 2.0;
351 let nbits = nx.to_bits();
352 exp = ((nbits >> 23) & 0xFF) as i32 - 32;
353 let frac = f32::from_bits((nbits & !(0xFFu32 << 23)) | (0x7Eu32 << 23));
354 return (if sign != 0 { -frac.abs() } else { frac }, exp - 0x7E);
355 }
356 let frac = f32::from_bits((bits & !(0xFFu32 << 23)) | (0x7Eu32 << 23));
357 (frac, exp - 0x7E)
358}
359
360pub fn frexp<T, D>(input: &Array<T, D>) -> FerrayResult<(Array<T, D>, Array<i32, D>)>
368where
369 T: Element + Float,
370 D: Dimension,
371{
372 use std::any::TypeId;
373
374 if TypeId::of::<T>() == TypeId::of::<f64>() {
375 let f64_input =
377 unsafe { &*std::ptr::from_ref::<Array<T, D>>(input).cast::<Array<f64, D>>() };
378 let mut mantissas = Vec::with_capacity(f64_input.size());
379 let mut exponents = Vec::with_capacity(f64_input.size());
380 for &x in f64_input.iter() {
381 let (m, e) = frexp_f64(x);
382 mantissas.push(m);
383 exponents.push(e);
384 }
385 let m_arr: Array<f64, D> = Array::from_vec(f64_input.dim().clone(), mantissas)?;
386 let e_arr = Array::from_vec(f64_input.dim().clone(), exponents)?;
387 let m_result = unsafe { crate::helpers::reinterpret_array::<f64, T, D>(m_arr) };
388 Ok((m_result, e_arr))
389 } else if TypeId::of::<T>() == TypeId::of::<f32>() {
390 let f32_input =
392 unsafe { &*std::ptr::from_ref::<Array<T, D>>(input).cast::<Array<f32, D>>() };
393 let mut mantissas = Vec::with_capacity(f32_input.size());
394 let mut exponents = Vec::with_capacity(f32_input.size());
395 for &x in f32_input.iter() {
396 let (m, e) = frexp_f32(x);
397 mantissas.push(m);
398 exponents.push(e);
399 }
400 let m_arr: Array<f32, D> = Array::from_vec(f32_input.dim().clone(), mantissas)?;
401 let e_arr = Array::from_vec(f32_input.dim().clone(), exponents)?;
402 let m_result = unsafe { crate::helpers::reinterpret_array::<f32, T, D>(m_arr) };
403 Ok((m_result, e_arr))
404 } else {
405 let mut mantissas = Vec::with_capacity(input.size());
407 let mut exponents = Vec::with_capacity(input.size());
408 for &x in input.iter() {
409 let x64 = x.to_f64().unwrap();
410 let (m64, e) = frexp_f64(x64);
411 mantissas.push(T::from(m64).unwrap());
412 exponents.push(e);
413 }
414 Ok((
415 Array::from_vec(input.dim().clone(), mantissas)?,
416 Array::from_vec(input.dim().clone(), exponents)?,
417 ))
418 }
419}
420
421pub fn modf<T, D>(input: &Array<T, D>) -> FerrayResult<(Array<T, D>, Array<T, D>)>
435where
436 T: Element + Float,
437 D: Dimension,
438{
439 let mut fracs = Vec::with_capacity(input.size());
440 let mut ints = Vec::with_capacity(input.size());
441 for &x in input.iter() {
442 if x.is_nan() {
443 fracs.push(x);
444 ints.push(x);
445 } else if x.is_infinite() {
446 let zero = <T as num_traits::Zero>::zero();
448 fracs.push(if x.is_sign_positive() { zero } else { -zero });
449 ints.push(x);
450 } else {
451 let i = x.trunc();
452 ints.push(i);
453 fracs.push(x - i);
454 }
455 }
456 Ok((
457 Array::from_vec(input.dim().clone(), fracs)?,
458 Array::from_vec(input.dim().clone(), ints)?,
459 ))
460}
461
462pub fn copysign<T, D>(x1: &Array<T, D>, x2: &Array<T, D>) -> FerrayResult<Array<T, D>>
464where
465 T: Element + Float,
466 D: Dimension,
467{
468 binary_elementwise_op(x1, x2, |a, b| {
469 let mag = a.abs();
470 if b.is_sign_negative() { -mag } else { mag }
471 })
472}
473
474pub fn float_power<T, D>(x1: &Array<T, D>, x2: &Array<T, D>) -> FerrayResult<Array<T, D>>
476where
477 T: Element + Float,
478 D: Dimension,
479{
480 binary_elementwise_op(x1, x2, T::powf)
481}
482
483pub fn maximum<T, D>(a: &Array<T, D>, b: &Array<T, D>) -> FerrayResult<Array<T, D>>
485where
486 T: Element + Float,
487 D: Dimension,
488{
489 binary_elementwise_op(a, b, |x, y| {
490 if x.is_nan() || y.is_nan() {
491 <T as Float>::nan()
492 } else if x >= y {
493 x
494 } else {
495 y
496 }
497 })
498}
499
500pub fn minimum<T, D>(a: &Array<T, D>, b: &Array<T, D>) -> FerrayResult<Array<T, D>>
502where
503 T: Element + Float,
504 D: Dimension,
505{
506 binary_elementwise_op(a, b, |x, y| {
507 if x.is_nan() || y.is_nan() {
508 <T as Float>::nan()
509 } else if x <= y {
510 x
511 } else {
512 y
513 }
514 })
515}
516
517pub fn fmax<T, D>(a: &Array<T, D>, b: &Array<T, D>) -> FerrayResult<Array<T, D>>
519where
520 T: Element + Float,
521 D: Dimension,
522{
523 binary_elementwise_op(a, b, |x, y| {
524 if x.is_nan() {
525 y
526 } else if y.is_nan() || x >= y {
527 x
528 } else {
529 y
530 }
531 })
532}
533
534pub fn fmin<T, D>(a: &Array<T, D>, b: &Array<T, D>) -> FerrayResult<Array<T, D>>
536where
537 T: Element + Float,
538 D: Dimension,
539{
540 binary_elementwise_op(a, b, |x, y| {
541 if x.is_nan() {
542 y
543 } else if y.is_nan() || x <= y {
544 x
545 } else {
546 y
547 }
548 })
549}
550
551#[cfg(feature = "f16")]
557pub fn isnan_f16<D>(input: &Array<half::f16, D>) -> FerrayResult<Array<bool, D>>
558where
559 D: Dimension,
560{
561 crate::helpers::unary_f16_to_bool_op(input, f32::is_nan)
562}
563
564#[cfg(feature = "f16")]
566pub fn isinf_f16<D>(input: &Array<half::f16, D>) -> FerrayResult<Array<bool, D>>
567where
568 D: Dimension,
569{
570 crate::helpers::unary_f16_to_bool_op(input, f32::is_infinite)
571}
572
573#[cfg(feature = "f16")]
575pub fn isfinite_f16<D>(input: &Array<half::f16, D>) -> FerrayResult<Array<bool, D>>
576where
577 D: Dimension,
578{
579 crate::helpers::unary_f16_to_bool_op(input, f32::is_finite)
580}
581
582#[cfg(feature = "f16")]
584pub fn clip_f16<D>(
585 input: &Array<half::f16, D>,
586 a_min: half::f16,
587 a_max: half::f16,
588) -> FerrayResult<Array<half::f16, D>>
589where
590 D: Dimension,
591{
592 let min_f32 = a_min.to_f32();
593 let max_f32 = a_max.to_f32();
594 if min_f32 > max_f32 {
595 return Err(FerrayError::invalid_value("clip: a_min must be <= a_max"));
596 }
597 crate::helpers::unary_f16_op(input, |x| {
598 if x < min_f32 {
599 min_f32
600 } else if x > max_f32 {
601 max_f32
602 } else {
603 x
604 }
605 })
606}
607
608#[cfg(feature = "f16")]
610pub fn nan_to_num_f16<D>(
611 input: &Array<half::f16, D>,
612 nan: Option<half::f16>,
613 posinf: Option<half::f16>,
614 neginf: Option<half::f16>,
615) -> FerrayResult<Array<half::f16, D>>
616where
617 D: Dimension,
618{
619 let nan_val = nan.unwrap_or(half::f16::ZERO).to_f32();
620 let posinf_val = posinf.unwrap_or(half::f16::MAX).to_f32();
621 let neginf_val = neginf.unwrap_or(half::f16::MIN).to_f32();
622 crate::helpers::unary_f16_op(input, |x| {
623 if x.is_nan() {
624 nan_val
625 } else if x.is_infinite() {
626 if x > 0.0 { posinf_val } else { neginf_val }
627 } else {
628 x
629 }
630 })
631}
632
633#[cfg(feature = "f16")]
635pub fn maximum_f16<D>(
636 a: &Array<half::f16, D>,
637 b: &Array<half::f16, D>,
638) -> FerrayResult<Array<half::f16, D>>
639where
640 D: Dimension,
641{
642 crate::helpers::binary_f16_op(a, b, |x, y| {
643 if x.is_nan() || y.is_nan() {
644 f32::NAN
645 } else if x >= y {
646 x
647 } else {
648 y
649 }
650 })
651}
652
653#[cfg(feature = "f16")]
655pub fn minimum_f16<D>(
656 a: &Array<half::f16, D>,
657 b: &Array<half::f16, D>,
658) -> FerrayResult<Array<half::f16, D>>
659where
660 D: Dimension,
661{
662 crate::helpers::binary_f16_op(a, b, |x, y| {
663 if x.is_nan() || y.is_nan() {
664 f32::NAN
665 } else if x <= y {
666 x
667 } else {
668 y
669 }
670 })
671}
672
673#[cfg(test)]
674mod tests {
675 use super::*;
676 use ferray_core::dimension::Ix1;
677
678 use crate::test_util::arr1;
679
680 fn arr1_i32(data: Vec<i32>) -> Array<i32, Ix1> {
681 let n = data.len();
682 Array::from_vec(Ix1::new([n]), data).unwrap()
683 }
684
685 #[test]
686 fn test_isnan() {
687 let a = arr1(vec![1.0, f64::NAN, 3.0]);
688 let r = isnan(&a).unwrap();
689 assert_eq!(r.as_slice().unwrap(), &[false, true, false]);
690 }
691
692 #[test]
693 fn test_isinf() {
694 let a = arr1(vec![1.0, f64::INFINITY, f64::NEG_INFINITY]);
695 let r = isinf(&a).unwrap();
696 assert_eq!(r.as_slice().unwrap(), &[false, true, true]);
697 }
698
699 #[test]
700 fn test_isfinite() {
701 let a = arr1(vec![1.0, f64::INFINITY, f64::NAN]);
702 let r = isfinite(&a).unwrap();
703 assert_eq!(r.as_slice().unwrap(), &[true, false, false]);
704 }
705
706 #[test]
707 fn test_isneginf() {
708 let a = arr1(vec![f64::NEG_INFINITY, f64::INFINITY, 0.0]);
709 let r = isneginf(&a).unwrap();
710 assert_eq!(r.as_slice().unwrap(), &[true, false, false]);
711 }
712
713 #[test]
714 fn test_isposinf() {
715 let a = arr1(vec![f64::NEG_INFINITY, f64::INFINITY, 0.0]);
716 let r = isposinf(&a).unwrap();
717 assert_eq!(r.as_slice().unwrap(), &[false, true, false]);
718 }
719
720 #[test]
721 fn test_nan_to_num() {
722 let a = arr1(vec![f64::NAN, f64::INFINITY, f64::NEG_INFINITY, 1.0]);
723 let r = nan_to_num(&a, None, None, None).unwrap();
724 let s = r.as_slice().unwrap();
725 assert_eq!(s[0], 0.0);
726 assert!(s[1].is_finite() && s[1] > 0.0);
727 assert!(s[2].is_finite() && s[2] < 0.0);
728 assert_eq!(s[3], 1.0);
729 }
730
731 #[test]
732 fn test_clip() {
733 let a = arr1(vec![-1.0, 0.5, 1.5, 3.0]);
734 let r = clip(&a, 0.0, 2.0).unwrap();
735 assert_eq!(r.as_slice().unwrap(), &[0.0, 0.5, 1.5, 2.0]);
736 }
737
738 #[test]
739 fn test_clip_ord_integer() {
740 let a = Array::<i32, Ix1>::from_vec(Ix1::new([5]), vec![-10, 0, 5, 100, 255]).unwrap();
741 let r = clip_ord(&a, 0, 200).unwrap();
742 assert_eq!(r.as_slice().unwrap(), &[0, 0, 5, 100, 200]);
743 }
744
745 #[test]
746 fn test_clip_ord_u8() {
747 let a = Array::<u8, Ix1>::from_vec(Ix1::new([4]), vec![0, 50, 200, 255]).unwrap();
748 let r = clip_ord(&a, 10, 128).unwrap();
749 assert_eq!(r.as_slice().unwrap(), &[10, 50, 128, 128]);
750 }
751
752 #[test]
753 fn test_signbit() {
754 let a = arr1(vec![-1.0, 0.0, 1.0]);
755 let r = signbit(&a).unwrap();
756 assert_eq!(r.as_slice().unwrap(), &[true, false, false]);
757 }
758
759 #[test]
760 fn test_copysign() {
761 let a = arr1(vec![1.0, -2.0, 3.0]);
762 let b = arr1(vec![-1.0, 1.0, -1.0]);
763 let r = copysign(&a, &b).unwrap();
764 assert_eq!(r.as_slice().unwrap(), &[-1.0, 2.0, -3.0]);
765 }
766
767 #[test]
768 fn test_maximum() {
769 let a = arr1(vec![1.0, 5.0, 3.0]);
770 let b = arr1(vec![4.0, 2.0, 3.0]);
771 let r = maximum(&a, &b).unwrap();
772 assert_eq!(r.as_slice().unwrap(), &[4.0, 5.0, 3.0]);
773 }
774
775 #[test]
776 fn test_minimum() {
777 let a = arr1(vec![1.0, 5.0, 3.0]);
778 let b = arr1(vec![4.0, 2.0, 3.0]);
779 let r = minimum(&a, &b).unwrap();
780 assert_eq!(r.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
781 }
782
783 #[test]
784 fn test_maximum_nan_propagation() {
785 let a = arr1(vec![1.0, f64::NAN]);
786 let b = arr1(vec![2.0, 3.0]);
787 let r = maximum(&a, &b).unwrap();
788 let s = r.as_slice().unwrap();
789 assert_eq!(s[0], 2.0);
790 assert!(s[1].is_nan());
791 }
792
793 #[test]
794 fn test_fmax_ignores_nan() {
795 let a = arr1(vec![1.0, f64::NAN]);
796 let b = arr1(vec![2.0, 3.0]);
797 let r = fmax(&a, &b).unwrap();
798 let s = r.as_slice().unwrap();
799 assert_eq!(s[0], 2.0);
800 assert_eq!(s[1], 3.0);
801 }
802
803 #[test]
804 fn test_fmin_ignores_nan() {
805 let a = arr1(vec![1.0, f64::NAN]);
806 let b = arr1(vec![2.0, 3.0]);
807 let r = fmin(&a, &b).unwrap();
808 let s = r.as_slice().unwrap();
809 assert_eq!(s[0], 1.0);
810 assert_eq!(s[1], 3.0);
811 }
812
813 #[test]
814 fn test_float_power() {
815 let a = arr1(vec![2.0, 3.0]);
816 let b = arr1(vec![3.0, 2.0]);
817 let r = float_power(&a, &b).unwrap();
818 assert_eq!(r.as_slice().unwrap(), &[8.0, 9.0]);
819 }
820
821 #[test]
822 fn test_spacing() {
823 let a = arr1(vec![1.0]);
824 let r = spacing(&a).unwrap();
825 let s = r.as_slice().unwrap();
826 assert_eq!(s[0], f64::EPSILON);
828 }
829
830 #[test]
831 fn test_spacing_zero() {
832 let a = arr1(vec![0.0]);
833 let r = spacing(&a).unwrap();
834 let s = r.as_slice().unwrap();
835 assert_eq!(s[0], f64::from_bits(1));
837 }
838
839 #[test]
840 fn test_spacing_nan_inf() {
841 let a = arr1(vec![f64::NAN, f64::INFINITY, f64::NEG_INFINITY]);
842 let r = spacing(&a).unwrap();
843 let s = r.as_slice().unwrap();
844 assert!(s[0].is_nan());
845 assert!(s[1].is_nan());
846 assert!(s[2].is_nan());
847 }
848
849 #[test]
850 fn test_ldexp() {
851 let x = arr1(vec![1.0, 2.0]);
852 let n = arr1_i32(vec![2, 3]);
853 let r = ldexp(&x, &n).unwrap();
854 let s = r.as_slice().unwrap();
855 assert!((s[0] - 4.0).abs() < 1e-12);
856 assert!((s[1] - 16.0).abs() < 1e-12);
857 }
858
859 #[test]
860 fn test_ldexp_broadcasts() {
861 use ferray_core::dimension::Ix2;
862 let x = Array::<f64, Ix2>::from_vec(Ix2::new([2, 1]), vec![1.0, 3.0]).unwrap();
863 let n = Array::<i32, Ix2>::from_vec(Ix2::new([1, 3]), vec![1, 2, 3]).unwrap();
864 let r = ldexp(&x, &n).unwrap();
865 assert_eq!(r.shape(), &[2, 3]);
866 let v: Vec<f64> = r.iter().copied().collect();
868 assert_eq!(v, vec![2.0, 4.0, 8.0, 6.0, 12.0, 24.0]);
869 }
870
871 #[test]
872 fn test_frexp() {
873 let a = arr1(vec![4.0]);
874 let (m, e) = frexp(&a).unwrap();
875 let ms = m.as_slice().unwrap();
876 let es = e.as_slice().unwrap();
877 assert!((ms[0] - 0.5).abs() < 1e-12);
879 assert_eq!(es[0], 3);
880 }
881
882 #[test]
883 fn test_nextafter_zero_toward_positive() {
884 let a = arr1(vec![0.0]);
885 let b = arr1(vec![1.0]);
886 let r = nextafter(&a, &b).unwrap();
887 let s = r.as_slice().unwrap();
888 assert_eq!(s[0], f64::from_bits(1));
890 }
891
892 #[test]
893 fn test_nextafter_zero_toward_negative() {
894 let a = arr1(vec![0.0]);
895 let b = arr1(vec![-1.0]);
896 let r = nextafter(&a, &b).unwrap();
897 let s = r.as_slice().unwrap();
898 assert_eq!(s[0], f64::from_bits(1u64 | (1u64 << 63)));
900 }
901
902 #[test]
903 fn test_nextafter_equal() {
904 let a = arr1(vec![1.0]);
905 let b = arr1(vec![1.0]);
906 let r = nextafter(&a, &b).unwrap();
907 let s = r.as_slice().unwrap();
908 assert_eq!(s[0], 1.0);
909 }
910
911 #[test]
912 fn test_nextafter_nan() {
913 let a = arr1(vec![f64::NAN, 1.0]);
914 let b = arr1(vec![1.0, f64::NAN]);
915 let r = nextafter(&a, &b).unwrap();
916 let s = r.as_slice().unwrap();
917 assert!(s[0].is_nan());
918 assert!(s[1].is_nan());
919 }
920
921 #[test]
922 fn test_nextafter_one_toward_two() {
923 let a = arr1(vec![1.0]);
924 let b = arr1(vec![2.0]);
925 let r = nextafter(&a, &b).unwrap();
926 let s = r.as_slice().unwrap();
927 assert_eq!(s[0], 1.0 + f64::EPSILON);
929 }
930
931 #[test]
932 fn test_nextafter_negative() {
933 let a = arr1(vec![-1.0]);
934 let b = arr1(vec![-2.0]);
935 let r = nextafter(&a, &b).unwrap();
936 let s = r.as_slice().unwrap();
937 assert_eq!(s[0], -1.0 - f64::EPSILON);
939 }
940
941 #[cfg(feature = "f16")]
942 mod f16_tests {
943 use super::*;
944
945 fn arr1_f16(data: &[f32]) -> Array<half::f16, Ix1> {
946 let n = data.len();
947 let vals: Vec<half::f16> = data.iter().map(|&x| half::f16::from_f32(x)).collect();
948 Array::from_vec(Ix1::new([n]), vals).unwrap()
949 }
950
951 #[test]
952 fn test_isnan_f16() {
953 let a = arr1_f16(&[1.0, f32::NAN, 3.0]);
954 let r = isnan_f16(&a).unwrap();
955 assert_eq!(r.as_slice().unwrap(), &[false, true, false]);
956 }
957
958 #[test]
959 fn test_isinf_f16() {
960 let a = arr1_f16(&[1.0, f32::INFINITY, f32::NEG_INFINITY]);
961 let r = isinf_f16(&a).unwrap();
962 assert_eq!(r.as_slice().unwrap(), &[false, true, true]);
963 }
964
965 #[test]
966 fn test_isfinite_f16() {
967 let a = arr1_f16(&[1.0, f32::INFINITY, f32::NAN]);
968 let r = isfinite_f16(&a).unwrap();
969 assert_eq!(r.as_slice().unwrap(), &[true, false, false]);
970 }
971
972 #[test]
973 fn test_clip_f16() {
974 let a = arr1_f16(&[-1.0, 0.5, 1.5, 3.0]);
975 let r = clip_f16(&a, half::f16::from_f32(0.0), half::f16::from_f32(2.0)).unwrap();
976 let s = r.as_slice().unwrap();
977 assert!((s[0].to_f32() - 0.0).abs() < 0.01);
978 assert!((s[1].to_f32() - 0.5).abs() < 0.01);
979 assert!((s[2].to_f32() - 1.5).abs() < 0.01);
980 assert!((s[3].to_f32() - 2.0).abs() < 0.01);
981 }
982
983 #[test]
984 fn test_nan_to_num_f16() {
985 let a = arr1_f16(&[f32::NAN, 1.0]);
986 let r = nan_to_num_f16(&a, None, None, None).unwrap();
987 let s = r.as_slice().unwrap();
988 assert_eq!(s[0].to_f32(), 0.0);
989 assert!((s[1].to_f32() - 1.0).abs() < 0.01);
990 }
991
992 #[test]
993 fn test_maximum_f16() {
994 let a = arr1_f16(&[1.0, 5.0, 3.0]);
995 let b = arr1_f16(&[4.0, 2.0, 3.0]);
996 let r = maximum_f16(&a, &b).unwrap();
997 let s = r.as_slice().unwrap();
998 assert!((s[0].to_f32() - 4.0).abs() < 0.01);
999 assert!((s[1].to_f32() - 5.0).abs() < 0.01);
1000 assert!((s[2].to_f32() - 3.0).abs() < 0.01);
1001 }
1002
1003 #[test]
1004 fn test_minimum_f16() {
1005 let a = arr1_f16(&[1.0, 5.0, 3.0]);
1006 let b = arr1_f16(&[4.0, 2.0, 3.0]);
1007 let r = minimum_f16(&a, &b).unwrap();
1008 let s = r.as_slice().unwrap();
1009 assert!((s[0].to_f32() - 1.0).abs() < 0.01);
1010 assert!((s[1].to_f32() - 2.0).abs() < 0.01);
1011 assert!((s[2].to_f32() - 3.0).abs() < 0.01);
1012 }
1013 }
1014
1015 #[test]
1018 fn test_modf_positive() {
1019 let a = arr1(vec![3.5, 1.25, 0.0]);
1020 let (frac, int) = modf(&a).unwrap();
1021 let f = frac.as_slice().unwrap();
1022 let i = int.as_slice().unwrap();
1023 assert!((f[0] - 0.5).abs() < 1e-12);
1024 assert!((f[1] - 0.25).abs() < 1e-12);
1025 assert_eq!(f[2], 0.0);
1026 assert_eq!(i, &[3.0, 1.0, 0.0]);
1027 }
1028
1029 #[test]
1030 fn test_modf_negative() {
1031 let a = arr1(vec![-3.5, -1.25]);
1032 let (frac, int) = modf(&a).unwrap();
1033 let f = frac.as_slice().unwrap();
1034 let i = int.as_slice().unwrap();
1035 assert!((f[0] - (-0.5)).abs() < 1e-12);
1036 assert!((f[1] - (-0.25)).abs() < 1e-12);
1037 assert_eq!(i, &[-3.0, -1.0]);
1038 }
1039
1040 #[test]
1041 fn test_modf_nan() {
1042 let a = arr1(vec![f64::NAN]);
1043 let (frac, int) = modf(&a).unwrap();
1044 assert!(frac.as_slice().unwrap()[0].is_nan());
1045 assert!(int.as_slice().unwrap()[0].is_nan());
1046 }
1047
1048 #[test]
1049 fn test_modf_infinity() {
1050 let a = arr1(vec![f64::INFINITY, f64::NEG_INFINITY]);
1051 let (frac, int) = modf(&a).unwrap();
1052 let f = frac.as_slice().unwrap();
1053 let i = int.as_slice().unwrap();
1054 assert_eq!(f[0], 0.0);
1055 assert!(f[0].is_sign_positive());
1056 assert_eq!(f[1], 0.0);
1057 assert!(f[1].is_sign_negative());
1058 assert!(i[0].is_infinite() && i[0].is_sign_positive());
1059 assert!(i[1].is_infinite() && i[1].is_sign_negative());
1060 }
1061
1062 #[test]
1063 fn test_modf_f32() {
1064 let a: Array<f32, Ix1> = Array::from_vec(Ix1::new([3]), vec![2.75_f32, -0.5, 1.0]).unwrap();
1065 let (frac, int) = modf(&a).unwrap();
1066 let f = frac.as_slice().unwrap();
1067 let i = int.as_slice().unwrap();
1068 assert!((f[0] - 0.75).abs() < 1e-6);
1069 assert!((f[1] - (-0.5)).abs() < 1e-6);
1070 assert_eq!(f[2], 0.0);
1071 assert_eq!(i, &[2.0_f32, 0.0, 1.0]);
1072 }
1073}