Skip to content

Commit 5826484

Browse files
committed
sys/phydat: avoid use of pow()
We just use a simple look-up table for the 10^x exponents that do not overflow the range of int16_t. In addition, we saturate on overflows.
1 parent b6d0480 commit 5826484

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

sys/phydat/phydat_unix.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
*/
88

99
#include <stdint.h>
10-
#include <math.h>
1110

11+
#include "macros/math.h"
12+
#include "container.h"
1213
#include "phydat.h"
1314

1415
/**
@@ -18,14 +19,36 @@
1819
static int16_t month_to_yday[] = { 0, 31, -306, -275, -245, -214,
1920
-184, -153, -122, -92, -61, -31 };
2021

21-
static inline int16_t phydat_unscale(int16_t value, int16_t scale)
22+
static int16_t phydat_unscale(int16_t value, int16_t scale)
2223
{
24+
static const int16_t tenmap[] = {10, 100, 1000, 10000 };
25+
26+
if (value == 0) {
27+
return 0;
28+
}
29+
30+
/* when out of range anyway, we just saturate to max */
31+
if (scale > (int16_t)ARRAY_SIZE(tenmap)) {
32+
return INT16_MAX;
33+
}
34+
35+
/* same, but lower end of the range */
36+
if (scale < -(int16_t)ARRAY_SIZE(tenmap)) {
37+
return 0;
38+
}
39+
2340
if (scale > 0) {
24-
return value * pow(10, scale);
41+
size_t idx = scale - 1;
42+
if (__builtin_mul_overflow(value, tenmap[idx], &value)) {
43+
/* result would overflow, returning INT16_MAX instead */
44+
return INT16_MAX;
45+
}
46+
return value;
2547
}
2648

2749
if (scale < 0) {
28-
return value / pow(10, -scale);
50+
size_t idx = (-scale) - 1;
51+
return DIV_ROUND(value, tenmap[idx]);
2952
}
3053

3154
return value;

0 commit comments

Comments
 (0)