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,8 +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 , tmp_value , adjusted_value ;
167
- int cpu_round_mode ;
165
+ double exponent , tmp_value , tmp_value2 ;
168
166
169
167
if (!zend_finite (value ) || value == 0.0 ) {
170
168
return value ;
@@ -181,30 +179,29 @@ PHPAPI double _php_math_round(double value, int places, int mode) {
181
179
* 0.285 * 10000000000 => 2849999999.9999995
182
180
* floor(0.285 * 10000000000) => 2849999999
183
181
*
184
- * Therefore, change the CPU rounding mode to away from 0 only from
185
- * 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.
186
186
* e.g.
187
- * 0.285 * 10000000000 => 2850000000.0
188
- * floor(0.285 * 10000000000) => 2850000000
189
- *
190
- * Using `if` twice to prevent accidental optimization with llvm 15.0.0.
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
191
192
*/
192
- bool val_is_positive_or_zero = value >= 0.0 ;
193
- cpu_round_mode = fegetround ();
194
- if ( val_is_positive_or_zero ) {
195
- fesetround ( FE_UPWARD ) ;
193
+
194
+ if ( value >= 0.0 ) {
195
+ tmp_value = floor ( places > 0 ? value * exponent : value / exponent );
196
+ tmp_value2 = tmp_value + 1.0 ;
196
197
} else {
197
- fesetround (FE_DOWNWARD );
198
+ tmp_value = ceil (places > 0 ? value * exponent : value / exponent );
199
+ tmp_value2 = tmp_value - 1.0 ;
198
200
}
199
201
200
- adjusted_value = places > 0 ? value * exponent : value / exponent ;
201
-
202
- if (val_is_positive_or_zero ) {
203
- tmp_value = floor (adjusted_value );
204
- } else {
205
- tmp_value = ceil (adjusted_value );
202
+ if ((places > 0 ? tmp_value2 / exponent : tmp_value2 * exponent ) == value ) {
203
+ tmp_value = tmp_value2 ;
206
204
}
207
- fesetround (cpu_round_mode );
208
205
209
206
/* This value is beyond our precision, so rounding it is pointless */
210
207
if (fabs (tmp_value ) >= 1e15 ) {
0 commit comments