7
7
//! performance seems to be better (based on icount) and it does not seem to experience rounding
8
8
//! errors on i386.
9
9
10
+ use super :: super :: support:: { FpResult , Status } ;
10
11
use super :: super :: { Float , Int , IntTy , MinInt } ;
11
12
12
13
pub fn ceil < F : Float > ( x : F ) -> F {
14
+ ceil_status ( x) . val
15
+ }
16
+
17
+ pub fn ceil_status < F : Float > ( x : F ) -> FpResult < F > {
13
18
let zero = IntTy :: < F > :: ZERO ;
14
19
15
20
let mut ix = x. to_bits ( ) ;
16
21
let e = x. exp_unbiased ( ) ;
17
22
18
23
// If the represented value has no fractional part, no truncation is needed.
19
24
if e >= F :: SIG_BITS as i32 {
20
- return x ;
25
+ return FpResult :: ok ( x ) ;
21
26
}
22
27
23
- if e >= 0 {
28
+ let status;
29
+ let res = if e >= 0 {
24
30
// |x| >= 1.0
25
-
26
31
let m = F :: SIG_MASK >> e. unsigned ( ) ;
27
32
if ( ix & m) == zero {
28
33
// Portion to be masked is already zero; no adjustment needed.
29
- return x ;
34
+ return FpResult :: ok ( x ) ;
30
35
}
31
36
32
37
// Otherwise, raise an inexact exception.
33
- force_eval ! ( x + F :: MAX ) ;
38
+ status = Status :: INEXACT ;
34
39
35
40
if x. is_sign_positive ( ) {
36
41
ix += m;
@@ -40,7 +45,11 @@ pub fn ceil<F: Float>(x: F) -> F {
40
45
F :: from_bits ( ix)
41
46
} else {
42
47
// |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0).
43
- force_eval ! ( x + F :: MAX ) ;
48
+ if ix & F :: SIG_MASK == F :: Int :: ZERO {
49
+ status = Status :: OK ;
50
+ } else {
51
+ status = Status :: INEXACT ;
52
+ }
44
53
45
54
if x. is_sign_negative ( ) {
46
55
// -1.0 < x <= -0.0; rounding up goes toward -0.0.
@@ -52,18 +61,30 @@ pub fn ceil<F: Float>(x: F) -> F {
52
61
// +0.0 remains unchanged
53
62
x
54
63
}
55
- }
64
+ } ;
65
+
66
+ FpResult :: new ( res, status)
56
67
}
57
68
58
69
#[ cfg( test) ]
59
70
mod tests {
60
71
use super :: * ;
72
+ use crate :: support:: Hexf ;
61
73
62
74
/// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil
63
- fn spec_test < F : Float > ( ) {
64
- // Not Asserted: that the current rounding mode has no effect.
65
- for f in [ F :: ZERO , F :: NEG_ZERO , F :: INFINITY , F :: NEG_INFINITY ] . iter ( ) . copied ( ) {
66
- assert_biteq ! ( ceil( f) , f) ;
75
+ fn spec_test < F : Float > ( cases : & [ ( F , F , Status ) ] ) {
76
+ let roundtrip = [ F :: ZERO , F :: ONE , F :: NEG_ONE , F :: NEG_ZERO , F :: INFINITY , F :: NEG_INFINITY ] ;
77
+
78
+ for x in roundtrip {
79
+ let FpResult { val, status } = ceil_status ( x) ;
80
+ assert_biteq ! ( val, x, "{}" , Hexf ( x) ) ;
81
+ assert_eq ! ( status, Status :: OK , "{}" , Hexf ( x) ) ;
82
+ }
83
+
84
+ for & ( x, res, res_stat) in cases {
85
+ let FpResult { val, status } = ceil_status ( x) ;
86
+ assert_biteq ! ( val, res, "{}" , Hexf ( x) ) ;
87
+ assert_eq ! ( status, res_stat, "{}" , Hexf ( x) ) ;
67
88
}
68
89
}
69
90
@@ -72,7 +93,17 @@ mod tests {
72
93
#[ test]
73
94
#[ cfg( f16_enabled) ]
74
95
fn spec_tests_f16 ( ) {
75
- spec_test :: < f16 > ( ) ;
96
+ let cases = [
97
+ ( 0.1 , 1.0 , Status :: INEXACT ) ,
98
+ ( -0.1 , -0.0 , Status :: INEXACT ) ,
99
+ ( 0.9 , 1.0 , Status :: INEXACT ) ,
100
+ ( -0.9 , -0.0 , Status :: INEXACT ) ,
101
+ ( 1.1 , 2.0 , Status :: INEXACT ) ,
102
+ ( -1.1 , -1.0 , Status :: INEXACT ) ,
103
+ ( 1.9 , 2.0 , Status :: INEXACT ) ,
104
+ ( -1.9 , -1.0 , Status :: INEXACT ) ,
105
+ ] ;
106
+ spec_test :: < f16 > ( & cases) ;
76
107
}
77
108
78
109
#[ test]
@@ -83,7 +114,17 @@ mod tests {
83
114
84
115
#[ test]
85
116
fn spec_tests_f32 ( ) {
86
- spec_test :: < f32 > ( ) ;
117
+ let cases = [
118
+ ( 0.1 , 1.0 , Status :: INEXACT ) ,
119
+ ( -0.1 , -0.0 , Status :: INEXACT ) ,
120
+ ( 0.9 , 1.0 , Status :: INEXACT ) ,
121
+ ( -0.9 , -0.0 , Status :: INEXACT ) ,
122
+ ( 1.1 , 2.0 , Status :: INEXACT ) ,
123
+ ( -1.1 , -1.0 , Status :: INEXACT ) ,
124
+ ( 1.9 , 2.0 , Status :: INEXACT ) ,
125
+ ( -1.9 , -1.0 , Status :: INEXACT ) ,
126
+ ] ;
127
+ spec_test :: < f32 > ( & cases) ;
87
128
}
88
129
89
130
#[ test]
@@ -94,12 +135,32 @@ mod tests {
94
135
95
136
#[ test]
96
137
fn spec_tests_f64 ( ) {
97
- spec_test :: < f64 > ( ) ;
138
+ let cases = [
139
+ ( 0.1 , 1.0 , Status :: INEXACT ) ,
140
+ ( -0.1 , -0.0 , Status :: INEXACT ) ,
141
+ ( 0.9 , 1.0 , Status :: INEXACT ) ,
142
+ ( -0.9 , -0.0 , Status :: INEXACT ) ,
143
+ ( 1.1 , 2.0 , Status :: INEXACT ) ,
144
+ ( -1.1 , -1.0 , Status :: INEXACT ) ,
145
+ ( 1.9 , 2.0 , Status :: INEXACT ) ,
146
+ ( -1.9 , -1.0 , Status :: INEXACT ) ,
147
+ ] ;
148
+ spec_test :: < f64 > ( & cases) ;
98
149
}
99
150
100
151
#[ test]
101
152
#[ cfg( f128_enabled) ]
102
153
fn spec_tests_f128 ( ) {
103
- spec_test :: < f128 > ( ) ;
154
+ let cases = [
155
+ ( 0.1 , 1.0 , Status :: INEXACT ) ,
156
+ ( -0.1 , -0.0 , Status :: INEXACT ) ,
157
+ ( 0.9 , 1.0 , Status :: INEXACT ) ,
158
+ ( -0.9 , -0.0 , Status :: INEXACT ) ,
159
+ ( 1.1 , 2.0 , Status :: INEXACT ) ,
160
+ ( -1.1 , -1.0 , Status :: INEXACT ) ,
161
+ ( 1.9 , 2.0 , Status :: INEXACT ) ,
162
+ ( -1.9 , -1.0 , Status :: INEXACT ) ,
163
+ ] ;
164
+ spec_test :: < f128 > ( & cases) ;
104
165
}
105
166
}
0 commit comments