Skip to content

Commit cc5c478

Browse files
committed
Fix Map function - IntegerDivideByZero esp8266#8938
Fixes: esp8266#8938 Also increase accuracy of mapping and fixing map issues with large values. Still only using integer operations. Test function to see absolute error compared to floating point map function using `double` precision floating point values. ```c++ # include <iostream> # include <string> long test_map(long x, long in_min, long in_max, long out_min, long out_max) { const double out_length = out_max - out_min; const double in_length = in_max - in_min; if (in_length == 0) { return in_min; } if (out_length == 0) { return out_min; } const double delta = x - in_min; const double value = (delta * out_length + (in_length / 2)) / in_length + out_min; // return std::round(value); return value; } long check(long x, long in_min, long in_max, long out_min, long out_max) { const long floatvalue = test_map(x, in_min, in_max, out_min, out_max); const long map_value = map(x, in_min, in_max, out_min, out_max); return floatvalue - map_value; } int main() { long input = 0; for (size_t i = 0; i < 15; ++i) { input = (i / 3) * 2500 - 1 + i % 3; const long values[] = { check(input, 0, 1000, 255, 0), check(input, 0, 1000, 0, 255), check(input, 10000, 0, 100, 10100), check(input, 10000, 0, 10100, 100), check(input, 10000, 0, 0, 1024), check(input, 10000, 0, 1024, 0), check(input, 1000, 0, 0, 10240), check(input, 1000, 0, 10240, 0), check(input, 0, 1000, 0, 10240), check(input, 0, 1000, 10240, 0), check(input, 0, 10000, 10240, 0), check(input, 10234567, -12345, 10234567, 100), check(input, 10000, 0, 10234567, 0), check(input, 50, 1, 10234567, 0) }; std::cout << input << ":"; constexpr size_t nrvalues = sizeof(values) / sizeof(values[0]); for (size_t i = 0; i < nrvalues; ++i) { std::cout << "\t" << values[i]; } std::cout << "\n"; } } ``` Output: ``` -1: 0 -1 0 0 0 -1 0 2 2 0 0 -1 2 2 0: 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 1: -1 0 0 0 -1 0 1 0 0 1 1 -1 0 0 2499: 1 -1 0 0 0 0 1 1 1 1 0 0 0 0 2500: 1 1 0 0 0 0 1 0 0 1 0 0 1 0 2501: 0 0 0 0 0 0 2 0 0 2 1 0 0 1 4999: 1 -1 0 0 0 0 1 1 1 1 0 0 0 0 5000: 1 0 0 0 0 0 1 0 0 1 0 0 1 1 5001: 0 0 0 0 0 0 2 0 0 2 1 0 1 0 7499: 1 -1 0 0 0 0 1 1 1 1 0 0 1 1 7500: 1 1 0 0 0 0 1 0 0 1 0 0 0 0 7501: 0 0 0 0 0 0 2 0 0 2 1 0 1 0 9999: 1 -1 0 0 0 -1 1 1 1 1 0 0 1 0 10000: 1 0 0 0 0 0 1 0 0 1 0 0 0 0 10001: 0 0 0 0 -1 0 2 0 0 2 2 0 0 1 ```
1 parent 521ae60 commit cc5c478

File tree

1 file changed

+60
-4
lines changed

1 file changed

+60
-4
lines changed

cores/esp8266/WMath.cpp

+60-4
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,67 @@ long secureRandom(long howsmall, long howbig) {
7272
}
7373

7474
long map(long x, long in_min, long in_max, long out_min, long out_max) {
75-
const long dividend = out_max - out_min;
76-
const long divisor = in_max - in_min;
77-
const long delta = x - in_min;
75+
const long out_length = out_max - out_min;
76+
const long in_length = in_max - in_min;
7877

79-
return (delta * dividend + (divisor / 2)) / divisor + out_min;
78+
if (in_length == 0) { return in_min; }
79+
80+
if (out_length == 0) { return out_min; }
81+
82+
long delta = x - in_min;
83+
84+
if (out_length == in_length) {
85+
return out_min + delta;
86+
}
87+
88+
if ((out_length < 0) && (in_length < 0)) {
89+
return map(x, in_max, in_min, out_max, out_min);
90+
} else if (out_length < 0) {
91+
return map(in_max - delta, in_min, in_max, out_max, out_min);
92+
} else if (in_length < 0) {
93+
return map(in_max - delta, in_max, in_min, out_min, out_max);
94+
}
95+
96+
// We now know in_min < in_max and out_min < out_max
97+
// Make sure x is within range of in_min ... in_max
98+
if ((x < in_min) || (x > in_max)) {
99+
long shift_factor = 0;
100+
101+
if (x < in_min) {
102+
const long before_min = in_min - x;
103+
shift_factor = -1 - (before_min / in_length);
104+
} else if (x > in_max) {
105+
const long passed_max = x - in_max;
106+
shift_factor = 1 + (passed_max / in_length);
107+
}
108+
109+
if (shift_factor != 0) {
110+
const long in_shift = shift_factor * in_length;
111+
const long out_shift = shift_factor * out_length;
112+
in_min += in_shift;
113+
in_max += in_shift;
114+
out_min += out_shift;
115+
out_max += out_shift;
116+
delta = x - in_min;
117+
}
118+
}
119+
120+
if (out_length > in_length) {
121+
// Map to larger range
122+
const long factor = out_length / in_length;
123+
const long error_mod = out_length % in_length;
124+
const long error = (delta * error_mod) / in_length;
125+
return (delta * factor) + out_min + error;
126+
}
127+
128+
// abs(out_length) < abs(in_length)
129+
// Map to smaller range
130+
const long factor = (in_length / out_length);
131+
132+
const long estimate_full = in_length / factor + out_min;
133+
const long error = (delta * (out_max - estimate_full)) / in_length;
134+
135+
return delta / factor + out_min + error;
80136
}
81137

82138
uint16_t makeWord(uint16_t w) {

0 commit comments

Comments
 (0)