61
61
62
62
#define MAX (a , b ) ((a) > (b) ? (a) : (b))
63
63
64
+ /*
65
+ * they are the max/min values, that can be converted to int64, such as:
66
+ * avm_float_t fvalue;
67
+ * int64_t ivalue = fvalue;
68
+ * // ivalue is guarnteed to be valid (>= INT64_MIN and <= INT64_MAX)
69
+ *
70
+ * They have been found with few test C programs (and while playing with bits)
71
+ * do not use `(avm_float_t) INT64_MIN` or `(avm_float_t) INT64_MAX`.
72
+ */
73
+ #ifdef AVM_USE_SINGLE_PRECISION
74
+ #define INT64_MIN_AS_AVM_FLOAT -9223372586610590720.0 // 0xDF000000 = -2^63
75
+ #define INT64_MAX_AS_AVM_FLOAT 9223371761976868863.0 // 0x5F000000 = 2^63
76
+ #else
77
+ #define INT64_MIN_AS_AVM_FLOAT -9223372036854776832.0 // 0xC3E0000000000000 = -2^63
78
+ #define INT64_MAX_AS_AVM_FLOAT 9223372036854775295.0 // 0x43DFFFFFFFFFFFFF = 2^62 * 1.1...1b
79
+ #endif
80
+
64
81
// intn.h and term.h headers are decoupled. We check here that sign enum values are matching.
65
82
_Static_assert (
66
83
(int ) TermPositiveInteger == (int ) IntNPositiveInteger , "term/intn definition mismatch" );
@@ -1246,28 +1263,37 @@ term bif_erlang_rem_2(Context *ctx, uint32_t fail_label, int live, term arg1, te
1246
1263
}
1247
1264
}
1248
1265
1266
+ static term float_to_integer_helper (
1267
+ avm_float_t fresult , Context * ctx , uint32_t fail_label , int live )
1268
+ {
1269
+ if (LIKELY (isfinite (fresult ))) {
1270
+ if ((fresult >= INT64_MIN_AS_AVM_FLOAT ) && (fresult <= INT64_MAX_AS_AVM_FLOAT )) {
1271
+ #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1
1272
+ return make_maybe_boxed_int64 (ctx , fail_label , live , fresult );
1273
+ #else
1274
+ return make_maybe_boxed_int (ctx , fail_label , live , fresult );
1275
+ #endif
1276
+ }
1277
+ }
1278
+
1279
+ RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
1280
+ }
1281
+
1249
1282
term bif_erlang_ceil_1 (Context * ctx , uint32_t fail_label , int live , term arg1 )
1250
1283
{
1251
1284
UNUSED (live );
1252
1285
1253
1286
if (term_is_float (arg1 )) {
1254
1287
avm_float_t fvalue = term_to_float (arg1 );
1255
- if ((fvalue <= INT64_MIN_AS_AVM_FLOAT ) || (fvalue >= INT64_MAX_AS_AVM_FLOAT )) {
1256
- RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
1257
- }
1258
1288
1259
- avm_int64_t result ;
1260
- #if AVM_USE_SINGLE_PRECISION
1261
- result = ceilf (fvalue );
1262
- #else
1263
- result = ceil (fvalue );
1264
- #endif
1289
+ avm_float_t fresult ;
1290
+ #if AVM_USE_SINGLE_PRECISION
1291
+ fresult = ceilf (fvalue );
1292
+ #else
1293
+ fresult = ceil (fvalue );
1294
+ #endif
1265
1295
1266
- #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1
1267
- return make_maybe_boxed_int64 (ctx , fail_label , live , result );
1268
- #else
1269
- return make_maybe_boxed_int (ctx , fail_label , live , result );
1270
- #endif
1296
+ return float_to_integer_helper (fresult , ctx , fail_label , live );
1271
1297
}
1272
1298
1273
1299
if (term_is_any_integer (arg1 )) {
@@ -1284,22 +1310,15 @@ term bif_erlang_floor_1(Context *ctx, uint32_t fail_label, int live, term arg1)
1284
1310
1285
1311
if (term_is_float (arg1 )) {
1286
1312
avm_float_t fvalue = term_to_float (arg1 );
1287
- if ((fvalue <= INT64_MIN_AS_AVM_FLOAT ) || (fvalue >= INT64_MAX_AS_AVM_FLOAT )) {
1288
- RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
1289
- }
1290
1313
1291
- avm_int64_t result ;
1292
- #if AVM_USE_SINGLE_PRECISION
1293
- result = floorf (fvalue );
1294
- #else
1295
- result = floor (fvalue );
1296
- #endif
1314
+ avm_float_t fresult ;
1315
+ #if AVM_USE_SINGLE_PRECISION
1316
+ fresult = floorf (fvalue );
1317
+ #else
1318
+ fresult = floor (fvalue );
1319
+ #endif
1297
1320
1298
- #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1
1299
- return make_maybe_boxed_int64 (ctx , fail_label , live , result );
1300
- #else
1301
- return make_maybe_boxed_int (ctx , fail_label , live , result );
1302
- #endif
1321
+ return float_to_integer_helper (fresult , ctx , fail_label , live );
1303
1322
}
1304
1323
1305
1324
if (term_is_any_integer (arg1 )) {
@@ -1316,22 +1335,15 @@ term bif_erlang_round_1(Context *ctx, uint32_t fail_label, int live, term arg1)
1316
1335
1317
1336
if (term_is_float (arg1 )) {
1318
1337
avm_float_t fvalue = term_to_float (arg1 );
1319
- if ((fvalue <= INT64_MIN_AS_AVM_FLOAT ) || (fvalue >= INT64_MAX_AS_AVM_FLOAT )) {
1320
- RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
1321
- }
1322
1338
1323
- avm_int64_t result ;
1324
- #if AVM_USE_SINGLE_PRECISION
1325
- result = llroundf (fvalue );
1326
- #else
1327
- result = llround (fvalue );
1328
- #endif
1339
+ avm_float_t fresult ;
1340
+ #if AVM_USE_SINGLE_PRECISION
1341
+ fresult = roundf (fvalue );
1342
+ #else
1343
+ fresult = round (fvalue );
1344
+ #endif
1329
1345
1330
- #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1
1331
- return make_maybe_boxed_int64 (ctx , fail_label , live , result );
1332
- #else
1333
- return make_maybe_boxed_int (ctx , fail_label , live , result );
1334
- #endif
1346
+ return float_to_integer_helper (fresult , ctx , fail_label , live );
1335
1347
}
1336
1348
1337
1349
if (term_is_any_integer (arg1 )) {
@@ -1348,22 +1360,15 @@ term bif_erlang_trunc_1(Context *ctx, uint32_t fail_label, int live, term arg1)
1348
1360
1349
1361
if (term_is_float (arg1 )) {
1350
1362
avm_float_t fvalue = term_to_float (arg1 );
1351
- if ((fvalue <= INT64_MIN_AS_AVM_FLOAT ) || (fvalue >= INT64_MAX_AS_AVM_FLOAT )) {
1352
- RAISE_ERROR_BIF (fail_label , OVERFLOW_ATOM );
1353
- }
1354
1363
1355
- avm_int64_t result ;
1356
- #if AVM_USE_SINGLE_PRECISION
1357
- result = truncf (fvalue );
1358
- #else
1359
- result = trunc (fvalue );
1360
- #endif
1364
+ avm_float_t fresult ;
1365
+ #if AVM_USE_SINGLE_PRECISION
1366
+ fresult = truncf (fvalue );
1367
+ #else
1368
+ fresult = trunc (fvalue );
1369
+ #endif
1361
1370
1362
- #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1
1363
- return make_maybe_boxed_int64 (ctx , fail_label , live , result );
1364
- #else
1365
- return make_maybe_boxed_int (ctx , fail_label , live , result );
1366
- #endif
1371
+ return float_to_integer_helper (fresult , ctx , fail_label , live );
1367
1372
}
1368
1373
1369
1374
if (term_is_any_integer (arg1 )) {
0 commit comments