27
27
#include <float.h>
28
28
#include <math.h>
29
29
#include <stdlib.h>
30
- #include <fenv.h>
31
30
32
31
#include "basic_functions.h"
33
32
@@ -163,9 +162,7 @@ static inline double php_round_helper(double integral, double value, double expo
163
162
* mode. For the specifics of the algorithm, see http://wiki.php.net/rfc/rounding
164
163
*/
165
164
PHPAPI double _php_math_round (double value , int places , int mode ) {
166
- double exponent ;
167
- double tmp_value ;
168
- int cpu_round_mode ;
165
+ double exponent , tmp_value , tmp_value2 ;
169
166
170
167
if (!zend_finite (value ) || value == 0.0 ) {
171
168
return value ;
@@ -182,21 +179,29 @@ PHPAPI double _php_math_round(double value, int places, int mode) {
182
179
* 0.285 * 10000000000 => 2849999999.9999995
183
180
* floor(0.285 * 10000000000) => 2849999999
184
181
*
185
- * Therefore, change the CPU rounding mode to away from 0 only from
186
- * fegetround to fesetround.
182
+ * Add 1 to the absolute value of the value adjusted by floor or ceil, use the
183
+ * exponent to return it to its original precision, and compare it with value.
184
+ * If it is equal to value, it is assumed that the absolute value is 1 smaller
185
+ * due to error and will be corrected.
187
186
* e.g.
188
- * 0.285 * 10000000000 => 2850000000.0
189
- * floor(0.285 * 10000000000) => 2850000000
187
+ * 0.285 * 10000000000 => 2849999999.9999995
188
+ * floor(0.285 * 10000000000) => 2849999999 (tmp_value)
189
+ * tmp_value2 = 2849999999 + 1 => 2850000000
190
+ * 2850000000 / 10000000000 == 0.285 => true
191
+ * tmp_value = tmp_value2
190
192
*/
191
- cpu_round_mode = fegetround ();
193
+
192
194
if (value >= 0.0 ) {
193
- fesetround ( FE_UPWARD );
194
- tmp_value = floor ( places > 0 ? value * exponent : value / exponent ) ;
195
+ tmp_value = floor ( places > 0 ? value * exponent : value / exponent );
196
+ tmp_value2 = tmp_value + 1.0 ;
195
197
} else {
196
- fesetround (FE_DOWNWARD );
197
- tmp_value = ceil (places > 0 ? value * exponent : value / exponent );
198
+ tmp_value = ceil (places > 0 ? value * exponent : value / exponent );
199
+ tmp_value2 = tmp_value - 1.0 ;
200
+ }
201
+
202
+ if ((places > 0 ? tmp_value2 / exponent : tmp_value2 * exponent ) == value ) {
203
+ tmp_value = tmp_value2 ;
198
204
}
199
- fesetround (cpu_round_mode );
200
205
201
206
/* This value is beyond our precision, so rounding it is pointless */
202
207
if (fabs (tmp_value ) >= 1e16 ) {
0 commit comments