add copy_sign and genericify abs
[vector-math.git] / src / algorithms / base.rs
1 use crate::{
2 prim::{PrimFloat, PrimUInt},
3 traits::{Context, Float, Make},
4 };
5
6 pub fn abs<
7 Ctx: Context,
8 VecF: Float<PrimFloat = PrimF> + Make<Context = Ctx>,
9 PrimF: PrimFloat<BitsType = PrimU>,
10 PrimU: PrimUInt,
11 >(
12 ctx: Ctx,
13 x: VecF,
14 ) -> VecF {
15 VecF::from_bits(x.to_bits() & ctx.make(!PrimF::SIGN_FIELD_MASK))
16 }
17
18 pub fn copy_sign<
19 Ctx: Context,
20 VecF: Float<PrimFloat = PrimF> + Make<Context = Ctx>,
21 PrimF: PrimFloat<BitsType = PrimU>,
22 PrimU: PrimUInt,
23 >(
24 ctx: Ctx,
25 mag: VecF,
26 sign: VecF,
27 ) -> VecF {
28 let mag_bits = mag.to_bits() & ctx.make(!PrimF::SIGN_FIELD_MASK);
29 let sign_bit = sign.to_bits() & ctx.make(PrimF::SIGN_FIELD_MASK);
30 VecF::from_bits(mag_bits | sign_bit)
31 }
32
33 #[cfg(test)]
34 mod tests {
35 use super::*;
36 use crate::{
37 f16::F16,
38 scalar::{Scalar, Value},
39 };
40
41 #[test]
42 #[cfg_attr(
43 not(feature = "f16"),
44 should_panic(expected = "f16 feature is not enabled")
45 )]
46 fn test_abs_f16() {
47 for bits in 0..=u16::MAX {
48 let v = F16::from_bits(bits);
49 let expected = v.abs();
50 let result = abs(Scalar, Value(v)).0;
51 assert_eq!(expected.to_bits(), result.to_bits());
52 }
53 }
54
55 #[test]
56 fn test_abs_f32() {
57 for bits in (0..=u32::MAX).step_by(10001) {
58 let v = f32::from_bits(bits);
59 let expected = v.abs();
60 let result = abs(Scalar, Value(v)).0;
61 assert_eq!(expected.to_bits(), result.to_bits());
62 }
63 }
64
65 #[test]
66 fn test_abs_f64() {
67 for bits in (0..=u64::MAX).step_by(100_000_000_000_001) {
68 let v = f64::from_bits(bits);
69 let expected = v.abs();
70 let result = abs(Scalar, Value(v)).0;
71 assert_eq!(expected.to_bits(), result.to_bits());
72 }
73 }
74
75 #[test]
76 #[cfg_attr(
77 not(feature = "f16"),
78 should_panic(expected = "f16 feature is not enabled")
79 )]
80 fn test_copy_sign_f16() {
81 #[track_caller]
82 fn check(mag_bits: u16, sign_bits: u16) {
83 let mag = F16::from_bits(mag_bits);
84 let sign = F16::from_bits(sign_bits);
85 let expected = mag.copysign(sign);
86 let result = copy_sign(Scalar, Value(mag), Value(sign)).0;
87 assert_eq!(expected.to_bits(), result.to_bits());
88 }
89 for mag_low_bits in 0..16 {
90 for mag_high_bits in 0..16 {
91 for sign_low_bits in 0..16 {
92 for sign_high_bits in 0..16 {
93 check(
94 mag_low_bits | (mag_high_bits << (16 - 4)),
95 sign_low_bits | (sign_high_bits << (16 - 4)),
96 );
97 }
98 }
99 }
100 }
101 }
102
103 #[test]
104 fn test_copy_sign_f32() {
105 #[track_caller]
106 fn check(mag_bits: u32, sign_bits: u32) {
107 let mag = f32::from_bits(mag_bits);
108 let sign = f32::from_bits(sign_bits);
109 let expected = mag.copysign(sign);
110 let result = copy_sign(Scalar, Value(mag), Value(sign)).0;
111 assert_eq!(expected.to_bits(), result.to_bits());
112 }
113 for mag_low_bits in 0..16 {
114 for mag_high_bits in 0..16 {
115 for sign_low_bits in 0..16 {
116 for sign_high_bits in 0..16 {
117 check(
118 mag_low_bits | (mag_high_bits << (32 - 4)),
119 sign_low_bits | (sign_high_bits << (32 - 4)),
120 );
121 }
122 }
123 }
124 }
125 }
126
127 #[test]
128 fn test_copy_sign_f64() {
129 #[track_caller]
130 fn check(mag_bits: u64, sign_bits: u64) {
131 let mag = f64::from_bits(mag_bits);
132 let sign = f64::from_bits(sign_bits);
133 let expected = mag.copysign(sign);
134 let result = copy_sign(Scalar, Value(mag), Value(sign)).0;
135 assert_eq!(expected.to_bits(), result.to_bits());
136 }
137 for mag_low_bits in 0..16 {
138 for mag_high_bits in 0..16 {
139 for sign_low_bits in 0..16 {
140 for sign_high_bits in 0..16 {
141 check(
142 mag_low_bits | (mag_high_bits << (64 - 4)),
143 sign_low_bits | (sign_high_bits << (64 - 4)),
144 );
145 }
146 }
147 }
148 }
149 }
150 }