machina_softfloat/ops/
round.rs1use crate::env::{ExcFlags, FloatEnv, RoundMode};
5use crate::parts::{
6 nan_propagate_one, round_pack, unpack, FloatClass, FloatParts,
7};
8use crate::types::{
9 BFloat16, Float128, Float16, Float32, Float64, FloatFormat, FloatX80,
10};
11
12const INT_BIT: u32 = 126;
13
14pub fn round_to_int<F: FloatFormat>(a: F, env: &mut FloatEnv) -> F {
17 let pa = unpack::<F>(a);
18
19 if pa.is_nan() {
20 let mut r = nan_propagate_one(&pa, env);
21 return round_pack::<F>(&mut r, env);
22 }
23
24 if pa.cls == FloatClass::Inf || pa.cls == FloatClass::Zero {
25 let mut r = pa;
26 return round_pack::<F>(&mut r, env);
27 }
28
29 if pa.exp >= F::FRAC_BITS as i32 {
32 let mut r = pa;
33 return round_pack::<F>(&mut r, env);
34 }
35
36 if pa.exp < 0 {
38 let rm = env.round_mode();
39 let inexact = pa.frac != 0;
40 if inexact {
41 env.raise(ExcFlags::INEXACT);
42 }
43
44 let round_up = match rm {
45 RoundMode::NearEven => {
46 pa.exp == -1 && pa.frac > (1u128 << INT_BIT)
49 }
50 RoundMode::NearMaxMag => pa.exp == -1,
51 RoundMode::ToZero => false,
52 RoundMode::Up => !pa.sign && inexact,
53 RoundMode::Down => pa.sign && inexact,
54 RoundMode::Odd => true,
55 };
56
57 if round_up {
58 let mut r = FloatParts {
60 sign: pa.sign,
61 exp: 0,
62 frac: 1u128 << INT_BIT,
63 cls: FloatClass::Normal,
64 };
65 return round_pack::<F>(&mut r, env);
66 }
67
68 let mut r = FloatParts {
70 sign: pa.sign,
71 exp: 0,
72 frac: 0,
73 cls: FloatClass::Zero,
74 };
75 return round_pack::<F>(&mut r, env);
76 }
77
78 let frac_shift = INT_BIT - pa.exp as u32;
81 let frac_mask = (1u128 << frac_shift) - 1;
82 let remainder = pa.frac & frac_mask;
83
84 if remainder == 0 {
85 let mut r = pa;
87 return round_pack::<F>(&mut r, env);
88 }
89
90 env.raise(ExcFlags::INEXACT);
91
92 let rm = env.round_mode();
93 let half = 1u128 << (frac_shift - 1);
94 let truncated = pa.frac & !frac_mask;
95 let lsb_set = (pa.frac >> frac_shift) & 1 != 0;
96 let increment = 1u128 << frac_shift;
97
98 let round_up = match rm {
99 RoundMode::NearEven => {
100 if remainder > half {
101 true
102 } else if remainder == half {
103 lsb_set
104 } else {
105 false
106 }
107 }
108 RoundMode::NearMaxMag => remainder >= half,
109 RoundMode::ToZero => false,
110 RoundMode::Up => !pa.sign,
111 RoundMode::Down => pa.sign,
112 RoundMode::Odd => {
113 !lsb_set
115 }
116 };
117
118 let frac = if round_up {
119 truncated.wrapping_add(increment)
120 } else {
121 truncated
122 };
123
124 let mut r = FloatParts {
125 sign: pa.sign,
126 exp: pa.exp,
127 frac,
128 cls: FloatClass::Normal,
129 };
130 round_pack::<F>(&mut r, env)
131}
132
133macro_rules! impl_round {
138 ($ty:ty) => {
139 impl $ty {
140 pub fn round_to_int(self, env: &mut FloatEnv) -> Self {
141 round_to_int::<Self>(self, env)
142 }
143 }
144 };
145}
146
147impl_round!(Float16);
148impl_round!(BFloat16);
149impl_round!(Float32);
150impl_round!(Float64);
151impl_round!(Float128);
152impl_round!(FloatX80);