From eb47be3bc80015fe5cfcc9db76b5d807acff5949 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Mon, 23 Feb 2026 20:37:17 +0100 Subject: [PATCH 1/6] fix #13, allow size to be 65535 (uint16_t) --- .github/workflows/arduino-lint.yml | 4 +- .github/workflows/arduino_test_runner.yml | 3 +- .github/workflows/jsoncheck.yml | 4 +- CHANGELOG.md | 9 ++ LICENSE | 2 +- MultiMap.h | 70 ++++++++++-- README.md | 78 ++++++++----- examples/multimap_BS_compare/output_0.3.0.txt | 105 ++++++++++++++++++ .../multimap_NTC_int_FAIL.ino | 4 +- .../multimap_distance/multimap_distance.ino | 2 +- .../output_0.3.0.txt | 39 +++++++ examples/multimap_timing/multimap_timing.ino | 1 - examples/multimap_timing/output_0.3.0.txt | 13 +++ library.json | 2 +- library.properties | 2 +- 15 files changed, 291 insertions(+), 47 deletions(-) create mode 100644 examples/multimap_BS_compare/output_0.3.0.txt create mode 100644 examples/multimap_distance_two_types/output_0.3.0.txt create mode 100644 examples/multimap_timing/output_0.3.0.txt diff --git a/.github/workflows/arduino-lint.yml b/.github/workflows/arduino-lint.yml index 7f8f4ef..aed264b 100644 --- a/.github/workflows/arduino-lint.yml +++ b/.github/workflows/arduino-lint.yml @@ -6,8 +6,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v4 - - uses: arduino/arduino-lint-action@v1 + - uses: actions/checkout@v6 + - uses: arduino/arduino-lint-action@v2 with: library-manager: update compliance: strict \ No newline at end of file diff --git a/.github/workflows/arduino_test_runner.yml b/.github/workflows/arduino_test_runner.yml index dbd0ce7..a2a5f07 100644 --- a/.github/workflows/arduino_test_runner.yml +++ b/.github/workflows/arduino_test_runner.yml @@ -6,9 +6,8 @@ jobs: runTest: runs-on: ubuntu-latest timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 diff --git a/.github/workflows/jsoncheck.yml b/.github/workflows/jsoncheck.yml index 1cbb5e2..2c52dc7 100644 --- a/.github/workflows/jsoncheck.yml +++ b/.github/workflows/jsoncheck.yml @@ -5,13 +5,15 @@ on: paths: - '**.json' pull_request: + paths: + - '**.json' jobs: test: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: json-syntax-check uses: limitusus/json-syntax-check@v2 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eb0a45..96cbf8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.3.0] - 2026-02-23 +- fix #13, allow size to be 65535 (uint16_t) +- add multi type **multiMapCache** to have all options. +- update readme.md +- update GitHub actions +- minor edits + +---- + ## [0.2.1] - 2025-07-17 - update readme.md - add multiMap_demo.ino diff --git a/LICENSE b/LICENSE index 35dd82b..6aad57a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2011-2025 Rob Tillaart +Copyright (c) 2011-2026 Rob Tillaart Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MultiMap.h b/MultiMap.h index f7bc1a4..48b8cdf 100644 --- a/MultiMap.h +++ b/MultiMap.h @@ -2,7 +2,7 @@ // // FILE: MultiMap.h // AUTHOR: Rob Tillaart -// VERSION: 0.2.1 +// VERSION: 0.3.0 // DATE: 2011-01-26 // PURPOSE: Arduino library for fast non-linear mapping or interpolation of values // URL: https://github.com/RobTillaart/MultiMap @@ -10,7 +10,7 @@ -#define MULTIMAP_LIB_VERSION (F("0.2.1")) +#define MULTIMAP_LIB_VERSION (F("0.3.0")) #include "Arduino.h" @@ -22,14 +22,14 @@ // // note: the in array must have increasing values template -T multiMap(T value, T* _in, T* _out, uint8_t size) +T multiMap(T value, T* _in, T* _out, uint16_t size) { // output is constrained to out array if (value <= _in[0]) return _out[0]; if (value >= _in[size-1]) return _out[size-1]; // search right interval - uint8_t pos = 1; // _in[0] already tested + uint16_t pos = 1; // _in[0] already tested while(value > _in[pos]) pos++; // this will handle all exact "points" in the _in array @@ -49,7 +49,7 @@ T multiMap(T value, T* _in, T* _out, uint8_t size) // e.g. 2 2 2 2 2 3 3 3 3 5 5 5 5 5 5 8 8 8 8 5 5 5 5 5 // implements a minimal cache of the lastValue. template -T multiMapCache(T value, T* _in, T* _out, uint8_t size) +T multiMapCache(T value, T* _in, T* _out, uint16_t size) { static T lastValue = -1; // possible bug for 1st call static T cache = -1; @@ -72,7 +72,7 @@ T multiMapCache(T value, T* _in, T* _out, uint8_t size) else { // search right interval; index 0 _in[0] already tested - uint8_t pos = 1; + uint16_t pos = 1; while(value > _in[pos]) pos++; // this will handle all exact "points" in the _in array @@ -99,7 +99,7 @@ T multiMapCache(T value, T* _in, T* _out, uint8_t size) // // note: the in array must have increasing values template -T multiMapBS(T value, T* _in, T* _out, uint8_t size) +T multiMapBS(T value, T* _in, T* _out, uint16_t size) { // output is constrained to out array if (value <= _in[0]) return _out[0]; @@ -110,7 +110,7 @@ T multiMapBS(T value, T* _in, T* _out, uint8_t size) uint16_t upper = size - 1; while (lower < upper - 1) { - uint8_t mid = (lower + upper) / 2; + uint16_t mid = (lower + upper) / 2; if (value >= _in[mid]) lower = mid; else upper = mid; } @@ -125,7 +125,7 @@ T multiMapBS(T value, T* _in, T* _out, uint8_t size) // // note: the in array must have increasing values template -T2 multiMap(T1 value, T1* _in, T2* _out, uint8_t size) +T2 multiMap(T1 value, T1* _in, T2* _out, uint16_t size) { // output is constrained to out array if (value <= _in[0]) return _out[0]; @@ -143,6 +143,56 @@ T2 multiMap(T1 value, T1* _in, T2* _out, uint8_t size) } +//////////////////////////////////////////////////////////////////////// +// +// MULTITYPE TYPE MULTIMAP CACHE - LINEAR SEARCH +// +// note: the in array must have increasing values +// performance optimized version if inputs do not change often +// e.g. 2 2 2 2 2 3 3 3 3 5 5 5 5 5 5 8 8 8 8 5 5 5 5 5 +// implements a minimal cache of the lastValue. +template +T2 multiMapCache(T1 value, T1* _in, T2* _out, uint16_t size) +{ + static T1 lastValue = -1; // possible bug for 1st call + static T2 cache = -1; + + if (value == lastValue) + { + return cache; + } + lastValue = value; + + // output is constrained to out array + if (value <= _in[0]) + { + cache = _out[0]; + } + else if (value >= _in[size-1]) + { + cache = _out[size-1]; + } + else + { + // search right interval; index 0 _in[0] already tested + uint16_t pos = 1; + while(value > _in[pos]) pos++; + + // this will handle all exact "points" in the _in array + if (value == _in[pos]) + { + cache = _out[pos]; + } + else + { + // interpolate in the right segment for the rest + cache = (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + } + } + return cache; +} + + //////////////////////////////////////////////////////////////////////// // // MULTITYPE MULTIMAP - BINARY SEARCH @@ -151,7 +201,7 @@ T2 multiMap(T1 value, T1* _in, T2* _out, uint8_t size) // // note: the in array must have increasing values template -T2 multiMapBS(T1 value, T1* _in, T2* _out, uint8_t size) +T2 multiMapBS(T1 value, T1* _in, T2* _out, uint16_t size) { // output is constrained to out array if (value <= _in[0]) return _out[0]; diff --git a/README.md b/README.md index 1dcbb08..0e9d9da 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Arduino library for fast non-linear mapping or interpolation of values. In Arduino applications often the 'raw' value of a sensor is mapped upon a more usable value. E.g. the value of analogRead() 0 .. 1023 is mapped onto 0 .. 5.0 Volt. -This is often done by the **map()** function which does a linear interpolation +This is often done by the **map()** function which does a linear interpolation with integer truncating. This means in code: @@ -27,36 +27,63 @@ This means in code: output = C1 + input * C2 ``` -As C1 and C2 are to be determined, Arduino has the **map()** function that calculates the -two variables runtime from two given mapping points (I1, O1) and (I2, O2). +As C1 and C2 are constants to be determined, Arduino has the **map()** function that +calculates the two variables runtime from two given mapping points (I1, O1) and (I2, O2). ```cpp output = map(input, I1, I2, O1, O2): ``` -In many cases when there is no linear mapping possible as the 'points' are not +In many cases there is no linear mapping possible as the 'points' are not on a single straight line. Think a logarithmic or some sine wave form. To solve this one needs non-linear math to calculate the output from a given input. -The **multiMap()** function simulates this math by approximating the non-linear function with multiple -linear line segments. -Of course this approximation introduces an error. -By increasing the number of points and choose their position strategically the average error -can and will be reduced. -An important feature of the **multiMap()** is that the points do not need to have the same -distance (non-equidistant). This allows to have more pointe where needed (curvy line) and +The **multiMap()** function simulates this math by approximating the non-linear function with +multiple linear line segments. +Of course this approximation introduces an error. +By increasing the number of points and choose their position strategically the average error +can and will be reduced. +An important feature of the **multiMap()** is that the points do not need to have the same +distance (non-equidistant). This allows to have more pointe where needed (curvy line) and less point where possible (straight lines). -Note: some functions are hard to approximate even with **multiMap()** as they go to infinity +Note: some functions are hard to approximate even with **multiMap()** as they go to infinity or have a singularity. Think of **tan(x)** around x = PI/2 (90°) or **sin(1/x)** around zero. -The function to approximate must be (mathematically) an injection. -This means that for every input value (in the given range) there is an output value. +The function to approximate must be (mathematically) an injection. +This means that for every input value (in the given range) there is an output value. However there might be more than one input value mapping onto the same output value. See - https://en.wikipedia.org/wiki/Bijection,_injection_and_surjection +### 0.3.0 + +Since 0.3.0 sizes of multiMap can exceed 256 elements, up to 65535 elements. +This is because the size has changed from an uint8_t => uint16_t. + +On an UNO R3 this type change improved performance. + +From **multimap_BS_compare.ino** version 0.2.1 versus 0.3.0. + +| version | size | t1 | t2 | ratio | +|:----------|:------:|--------:|--------:|----------:| +| 0.2.1 | 10 | 9476 | 9364 | 98.82 | +| 0.2.1 | 15 | 13348 | 12628 | 94.61 | +| 0.2.1 | 20 | 17808 | 15948 | 89.56 | +| 0.2.1 | 30 | 28476 | 22712 | 79.76 | +| 0.2.1 | 40 | 41516 | 29620 | 71.35 | +| 0.2.1 | 50 | 56896 | 36608 | 64.34 | +| | | | | | +| 0.3.0 | 10 | 9308 | 9344 | 100.39 | +| 0.3.0 | 15 | 12936 | 12588 | 97.31 | +| 0.3.0 | 20 | 17052 | 15892 | 93.20 | +| 0.3.0 | 30 | 26728 | 22608 | 84.59 | +| 0.3.0 | 40 | 38340 | 29476 | 76.88 | +| 0.3.0 | 50 | 51900 | 36420 | 70.17 | +| | | | | | + + ### Related Other mapping libraries and interesting links. @@ -86,14 +113,14 @@ The basic call for **multiMap()** is: output = Multimap(input, inputArray, outputArray, size); ``` -**multiMap()** needs two equally sized arrays representing the reference 'points' named +**multiMap()** needs two equally sized arrays representing the reference 'points' named **inputArray\[\]** and **outputArray\[\]** both of the **datatype**. **multiMap()** will do a lookup of the input value in the **inputArray\[\]**. If it cannot find the index of an exact point it will determine a weighted position between two points. This optional weighted point is used to interpolate a value from the data in the **outputArray\[\]**. -- The **inputArray\[\]** must have increasing values, +- The **inputArray\[\]** must have increasing values, there is no such restriction for the **output\[\]** array. - The values of the **inputArray\[\]** do not need to have the same distance (non-equidistant). E.g a sort of logarithmic input array like { 1, 10, 100, 1000 } is valid. @@ -109,7 +136,7 @@ This implies that usage of larger and more precise arrays will take more time. Furthermore "low" input values will be found faster than "high" values, so the function has no constant time execution. -To optimize performance a binary search version exists, see **multiMapBS()** below. +To optimize performance a binary search version exists, see **multiMapBS()** below. As every usage of **multiMap()** is unique one should always do a performance check to see if there is a substantial gain in the case at hand. In my experience there often is. @@ -123,9 +150,9 @@ Experimental 0.1.7 => use with care. It is a very similar function as **multiMap()** with the same interface. The main difference is that MMBS uses binary search instead of linear search. -Performance tests indicate that for array sizes of about 10 elements, -the **multiMapBS()** is on par with **multiMap()**. -This is an expected value as both need on average about 5 steps to find +Performance tests indicate that for array sizes of about 10 elements, +the **multiMapBS()** is on par with **multiMap()**. +This is an expected value as both need on average about 5 steps to find the right interval to interpolate. Be sure to do your own tests to see if MMBS improves your performance. @@ -141,7 +168,7 @@ The goal is to improve the performance by preventing searching a repeating input value over and over again. If the input sequence has a lot of repeating values e.g. 2 2 2 2 2 2 5 5 5 5 5 4 4 4 4 2 2 2 2 2 2 -MMC will be able to return the value from cache often. +MMC will be able to return the value from cache often. Otherwise keeping cache is overhead. Be sure to do your own tests to see if MMC improves your performance. @@ -156,7 +183,7 @@ It would allow a to test that value and improve the linear search. Experimental 0.2.0 => use with care. **multiMap()** or MMTT for short, is a very similar function as **multiMap()**. -The main difference is that MMTT uses two different types, typical the input +The main difference is that MMTT uses two different types, typical the input is an integer type and the output is a float or double type. It is expected that there will be a gain if two different sized integer types are used. So performance is platform specific. @@ -221,7 +248,7 @@ Please note the fail example as this shows that in the intern math overflow can - less parameter passing - **isInRange(value)**? - caching last value / position / index (does that help?) - - flag if input value was "IN_MIN" < input < "IN_MAX", + - flag if input value was "IN_MIN" < input < "IN_MAX", now it is constrained without user being informed. - Investigate a 2D multiMap, 3D multiMap - is it possible / feasible? (YES | ??) @@ -230,14 +257,15 @@ Please note the fail example as this shows that in the intern math overflow can - complex ==> complex (?) - X ==> { Y, Z } in fact 2 output arrays. - needs other API call. - - can be implemented with multiple single MM calls, + - can be implemented with multiple single MM calls, one per dimension. - can the single type version be implemented with the two type version? +- add cache variants for binary search? #### Wont - should the lookup tables be merged into one array of pairs? - - you cannot reuse e.g. the input array or the output array then. + - you cannot reuse e.g. the input array or the output array then. this would not improve the memory footprint. diff --git a/examples/multimap_BS_compare/output_0.3.0.txt b/examples/multimap_BS_compare/output_0.3.0.txt new file mode 100644 index 0000000..e9a2a90 --- /dev/null +++ b/examples/multimap_BS_compare/output_0.3.0.txt @@ -0,0 +1,105 @@ +BOARD: UNO R3 +IDE: 1.8.19 + + +Arduino\libraries\MultiMap\examples\multimap_BS_compare\multimap_BS_compare.ino +MULTIMAP_LIB_VERSION: 0.3.0 + +size t1 t2 ratio +4 5588 5600 100.21 +5 6160 6200 100.65 +6 6756 6820 100.95 +7 7368 7448 101.09 +8 7992 8076 101.05 +9 8636 8700 100.74 +10 9308 9344 100.39 +11 9996 9996 100.00 +12 10700 10644 99.48 +13 11424 11288 98.81 +14 12172 11944 98.13 +15 12936 12588 97.31 +16 13724 13232 96.42 +17 14524 13884 95.59 +18 15348 14552 94.81 +19 16192 15224 94.02 +20 17052 15892 93.20 +21 17936 16564 92.35 +22 18836 17232 91.48 +23 19748 17904 90.66 +24 20688 18580 89.81 +25 21648 19252 88.93 +26 22624 19928 88.08 +27 23620 20592 87.18 +28 24644 21260 86.27 +29 25680 21936 85.42 +30 26728 22608 84.59 +31 27804 23276 83.71 +32 28896 23952 82.89 +33 30008 24628 82.07 +34 31140 25320 81.31 +35 32296 26008 80.53 +36 33464 26700 79.79 +37 34652 27396 79.06 +38 35864 28088 78.32 +39 37096 28780 77.58 +40 38340 29476 76.88 +41 39612 30164 76.15 +42 40900 30860 75.45 +43 42204 31556 74.77 +44 43532 32252 74.09 +45 44880 32944 73.40 +46 46244 33640 72.74 +47 47624 34336 72.10 +48 49032 35028 71.44 +49 50452 35724 70.81 +50 51900 36420 70.17 +51 53356 37108 69.55 +52 54844 37804 68.93 +53 56340 38500 68.34 +54 57856 39196 67.75 +55 59400 39888 67.15 +56 60960 40580 66.57 +57 62536 41276 66.00 +58 64136 41972 65.44 +59 65748 42668 64.90 +60 67388 43360 64.34 +61 69044 44056 63.81 +62 70716 44756 63.29 +63 72412 45448 62.76 +64 74128 46144 62.25 +65 75856 46840 61.75 +66 77608 47552 61.27 +67 79384 48268 60.80 +68 81176 48976 60.33 +69 82980 49696 59.89 +70 84812 50408 59.43 +71 86656 51128 59.00 +72 88528 51844 58.56 +73 90416 52556 58.13 +74 92320 53276 57.71 +75 94248 53992 57.29 +76 96196 54704 56.87 +77 98156 55428 56.47 +78 100148 56132 56.05 +79 102144 56860 55.67 +80 104176 57572 55.26 +81 106220 58292 54.88 +82 108280 59008 54.50 +83 110360 59716 54.11 +84 112460 60436 53.74 +85 114580 61156 53.37 +86 116720 61872 53.01 +87 118876 62588 52.65 +88 121056 63304 52.29 +89 123252 64020 51.94 +90 125468 64736 51.60 +91 127700 65456 51.26 +92 129960 66172 50.92 +93 132236 66896 50.59 +94 134528 67608 50.26 +95 134696 67696 50.26 +96 134696 67724 50.28 +97 134692 67772 50.32 +98 134696 67776 50.32 +99 134692 67804 50.34 + diff --git a/examples/multimap_NTC_int_FAIL/multimap_NTC_int_FAIL.ino b/examples/multimap_NTC_int_FAIL/multimap_NTC_int_FAIL.ino index 1d06fff..a5d0a50 100644 --- a/examples/multimap_NTC_int_FAIL/multimap_NTC_int_FAIL.ino +++ b/examples/multimap_NTC_int_FAIL/multimap_NTC_int_FAIL.ino @@ -1,7 +1,7 @@ // // FILE: multimap_NTC_int_FAIL.ino // AUTHOR: Rob Tillaart -// PURPOSE: demo of faulty optimizing +// PURPOSE: demo of faulty optimizing // URL: https://github.com/RobTillaart/MultiMap // // NOTE: @@ -26,7 +26,7 @@ int in[] = { }; int out[] = { - -27315, -7165, -6069, -4981, -4397, -3850, -3554, -3216, -2572, -2295, -2008, -1737, -1462, -790, -143, 357, 808, 1634, 2430, 3264, + -27315, -7165, -6069, -4981, -4397, -3850, -3554, -3216, -2572, -2295, -2008, -1737, -1462, -790, -143, 357, 808, 1634, 2430, 3264, 3717, 4213, 4805, 5419, 5875, 6603, 7287, 8385, 9651, 11146, 12949, 18282, 30182 }; diff --git a/examples/multimap_distance/multimap_distance.ino b/examples/multimap_distance/multimap_distance.ino index a436738..4df12d0 100644 --- a/examples/multimap_distance/multimap_distance.ino +++ b/examples/multimap_distance/multimap_distance.ino @@ -4,7 +4,7 @@ // PURPOSE: demo // URL: https://github.com/RobTillaart/MultiMap // -// example simulates the lookup graph of a distance sensor +// example simulates the lookup graph of a distance sensor #include "MultiMap.h" diff --git a/examples/multimap_distance_two_types/output_0.3.0.txt b/examples/multimap_distance_two_types/output_0.3.0.txt new file mode 100644 index 0000000..72682e3 --- /dev/null +++ b/examples/multimap_distance_two_types/output_0.3.0.txt @@ -0,0 +1,39 @@ +BOARD: UNO R3 +IDE: 1.8.19 + +Arduino\libraries\MultiMap\examples\multimap_distance_two_types\multimap_distance_two_types.ino +MULTIMAP_LIB_VERSION: 0.3.0 + +80 150.00 150.00 150.00 +81 150.00 150.00 150.00 +82 150.00 150.00 150.00 +83 150.00 150.00 150.00 +84 150.00 150.00 150.00 +85 150.00 150.00 150.00 +86 150.00 150.00 150.00 +87 150.00 150.00 150.00 +88 150.00 150.00 150.00 +89 150.00 150.00 150.00 +90 150.00 150.00 150.00 + +... (reduced for readability) + +500 20.61 20.61 20.61 +501 20.51 20.51 20.51 +502 20.41 20.41 20.41 +503 20.31 20.31 20.31 +504 20.20 20.20 20.20 +505 20.10 20.10 20.10 +506 20.00 20.00 20.00 +507 20.00 20.00 20.00 +508 20.00 20.00 20.00 +509 20.00 20.00 20.00 +510 20.00 20.00 20.00 +511 20.00 20.00 20.00 + +TIME1: 191.48 +TIME2: 116.31 +TIME3: 116.19 + + +Done... diff --git a/examples/multimap_timing/multimap_timing.ino b/examples/multimap_timing/multimap_timing.ino index c765794..1094eb6 100644 --- a/examples/multimap_timing/multimap_timing.ino +++ b/examples/multimap_timing/multimap_timing.ino @@ -56,4 +56,3 @@ void loop() // -- END OF FILE -- - diff --git a/examples/multimap_timing/output_0.3.0.txt b/examples/multimap_timing/output_0.3.0.txt new file mode 100644 index 0000000..5ef900e --- /dev/null +++ b/examples/multimap_timing/output_0.3.0.txt @@ -0,0 +1,13 @@ + +BOARD: UNO R3 +IDE: 1.8.19 + +...Arduino\libraries\MultiMap\examples\multimap_timing\multimap_timing.ino +MULTIMAP_LIB_VERSION: 0.3.0 + +time : 20 +121.0000 +time : 88 +121.0909 + +done... diff --git a/library.json b/library.json index 3cd6d11..252a402 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/MultiMap.git" }, - "version": "0.2.1", + "version": "0.3.0", "license": "MIT", "frameworks": "*", "platforms": "*", diff --git a/library.properties b/library.properties index 0189ae1..e156e7c 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=MultiMap -version=0.2.1 +version=0.3.0 author=Rob Tillaart maintainer=Rob Tillaart sentence=Library for fast non-linear interpolation by means of two arrays. From 15baed0d7db614e56b0c302a9a2ea9a414d38a2a Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Mon, 23 Feb 2026 22:10:57 +0100 Subject: [PATCH 2/6] fix math overflow --- CHANGELOG.md | 1 + MultiMap.h | 13 +- README.md | 28 ++- examples/multimap_BS_compare/output_0.3.0.txt | 194 +++++++++--------- .../multimap_demo_big/multimap_demo_big.ino | 52 +++++ examples/multimap_timing/output_0.3.0.txt | 5 +- 6 files changed, 180 insertions(+), 113 deletions(-) create mode 100644 examples/multimap_demo_big/multimap_demo_big.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 96cbf8e..e898a98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [0.3.0] - 2026-02-23 - fix #13, allow size to be 65535 (uint16_t) +- fix truncating when using int result types (cast to float in math). - add multi type **multiMapCache** to have all options. - update readme.md - update GitHub actions diff --git a/MultiMap.h b/MultiMap.h index 48b8cdf..aea7af5 100644 --- a/MultiMap.h +++ b/MultiMap.h @@ -36,7 +36,7 @@ T multiMap(T value, T* _in, T* _out, uint16_t size) if (value == _in[pos]) return _out[pos]; // interpolate in the right segment for the rest - return (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + return T(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } @@ -83,7 +83,7 @@ T multiMapCache(T value, T* _in, T* _out, uint16_t size) else { // interpolate in the right segment for the rest - cache = (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + cache = T(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } } return cache; @@ -114,8 +114,7 @@ T multiMapBS(T value, T* _in, T* _out, uint16_t size) if (value >= _in[mid]) lower = mid; else upper = mid; } - - return (value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower]) + _out[lower]; + return T(float(value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower])) + _out[lower]; } @@ -139,7 +138,7 @@ T2 multiMap(T1 value, T1* _in, T2* _out, uint16_t size) if (value == _in[pos]) return _out[pos]; // interpolate in the right segment for the rest - return (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + return T2(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } @@ -186,7 +185,7 @@ T2 multiMapCache(T1 value, T1* _in, T2* _out, uint16_t size) else { // interpolate in the right segment for the rest - cache = (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + cache = T2(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } } return cache; @@ -217,7 +216,7 @@ T2 multiMapBS(T1 value, T1* _in, T2* _out, uint16_t size) else upper = mid; } - return (value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower]) + _out[lower]; + return T2(float(value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower])) + _out[lower]; } diff --git a/README.md b/README.md index 0e9d9da..30032df 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,19 @@ However there might be more than one input value mapping onto the same output va See - https://en.wikipedia.org/wiki/Bijection,_injection_and_surjection -### 0.3.0 +### 0.3.0 Breaking change + +This 0.3.0 version makes the previous versions obsolete. Since 0.3.0 sizes of multiMap can exceed 256 elements, up to 65535 elements. This is because the size has changed from an uint8_t => uint16_t. -On an UNO R3 this type change improved performance. +More important the internal math has an extra float cast as when using int types +there was sometimes an overflow in the interpolation (rare but wrong). + +On an UNO R3 this breaking change altered the performance. +Linear search got better, binary search got worse but is still +better than the linear search. From **multimap_BS_compare.ino** version 0.2.1 versus 0.3.0. @@ -74,13 +81,17 @@ From **multimap_BS_compare.ino** version 0.2.1 versus 0.3.0. | 0.2.1 | 30 | 28476 | 22712 | 79.76 | | 0.2.1 | 40 | 41516 | 29620 | 71.35 | | 0.2.1 | 50 | 56896 | 36608 | 64.34 | +| 0.2.1 | 70 | 94716 | 50700 | 53.53 | +| 0.2.1 | 90 | 141936 | 65136 | 45.89 | | | | | | | -| 0.3.0 | 10 | 9308 | 9344 | 100.39 | -| 0.3.0 | 15 | 12936 | 12588 | 97.31 | -| 0.3.0 | 20 | 17052 | 15892 | 93.20 | -| 0.3.0 | 30 | 26728 | 22608 | 84.59 | -| 0.3.0 | 40 | 38340 | 29476 | 76.88 | -| 0.3.0 | 50 | 51900 | 36420 | 70.17 | +| 0.3.0 | 10 | 10592 | 10688 | 100.91 | +| 0.3.0 | 15 | 14528 | 14736 | 101.43 | +| 0.3.0 | 20 | 18808 | 18868 | 100.32 | +| 0.3.0 | 30 | 28412 | 27240 | 95.87 | +| 0.3.0 | 40 | 39396 | 35784 | 90.83 | +| 0.3.0 | 50 | 51764 | 44428 | 85.83 | +| 0.3.0 | 70 | 80648 | 61864 | 76.71 | +| 0.3.0 | 90 | 115068 | 79640 | 69.21 | | | | | | | @@ -154,6 +165,7 @@ Performance tests indicate that for array sizes of about 10 elements, the **multiMapBS()** is on par with **multiMap()**. This is an expected value as both need on average about 5 steps to find the right interval to interpolate. +From 20 elements and up **multiMapBS()** is normally faster. Be sure to do your own tests to see if MMBS improves your performance. diff --git a/examples/multimap_BS_compare/output_0.3.0.txt b/examples/multimap_BS_compare/output_0.3.0.txt index e9a2a90..cf745f5 100644 --- a/examples/multimap_BS_compare/output_0.3.0.txt +++ b/examples/multimap_BS_compare/output_0.3.0.txt @@ -6,100 +6,102 @@ Arduino\libraries\MultiMap\examples\multimap_BS_compare\multimap_BS_compare.ino MULTIMAP_LIB_VERSION: 0.3.0 size t1 t2 ratio -4 5588 5600 100.21 -5 6160 6200 100.65 -6 6756 6820 100.95 -7 7368 7448 101.09 -8 7992 8076 101.05 -9 8636 8700 100.74 -10 9308 9344 100.39 -11 9996 9996 100.00 -12 10700 10644 99.48 -13 11424 11288 98.81 -14 12172 11944 98.13 -15 12936 12588 97.31 -16 13724 13232 96.42 -17 14524 13884 95.59 -18 15348 14552 94.81 -19 16192 15224 94.02 -20 17052 15892 93.20 -21 17936 16564 92.35 -22 18836 17232 91.48 -23 19748 17904 90.66 -24 20688 18580 89.81 -25 21648 19252 88.93 -26 22624 19928 88.08 -27 23620 20592 87.18 -28 24644 21260 86.27 -29 25680 21936 85.42 -30 26728 22608 84.59 -31 27804 23276 83.71 -32 28896 23952 82.89 -33 30008 24628 82.07 -34 31140 25320 81.31 -35 32296 26008 80.53 -36 33464 26700 79.79 -37 34652 27396 79.06 -38 35864 28088 78.32 -39 37096 28780 77.58 -40 38340 29476 76.88 -41 39612 30164 76.15 -42 40900 30860 75.45 -43 42204 31556 74.77 -44 43532 32252 74.09 -45 44880 32944 73.40 -46 46244 33640 72.74 -47 47624 34336 72.10 -48 49032 35028 71.44 -49 50452 35724 70.81 -50 51900 36420 70.17 -51 53356 37108 69.55 -52 54844 37804 68.93 -53 56340 38500 68.34 -54 57856 39196 67.75 -55 59400 39888 67.15 -56 60960 40580 66.57 -57 62536 41276 66.00 -58 64136 41972 65.44 -59 65748 42668 64.90 -60 67388 43360 64.34 -61 69044 44056 63.81 -62 70716 44756 63.29 -63 72412 45448 62.76 -64 74128 46144 62.25 -65 75856 46840 61.75 -66 77608 47552 61.27 -67 79384 48268 60.80 -68 81176 48976 60.33 -69 82980 49696 59.89 -70 84812 50408 59.43 -71 86656 51128 59.00 -72 88528 51844 58.56 -73 90416 52556 58.13 -74 92320 53276 57.71 -75 94248 53992 57.29 -76 96196 54704 56.87 -77 98156 55428 56.47 -78 100148 56132 56.05 -79 102144 56860 55.67 -80 104176 57572 55.26 -81 106220 58292 54.88 -82 108280 59008 54.50 -83 110360 59716 54.11 -84 112460 60436 53.74 -85 114580 61156 53.37 -86 116720 61872 53.01 -87 118876 62588 52.65 -88 121056 63304 52.29 -89 123252 64020 51.94 -90 125468 64736 51.60 -91 127700 65456 51.26 -92 129960 66172 50.92 -93 132236 66896 50.59 -94 134528 67608 50.26 -95 134696 67696 50.26 -96 134696 67724 50.28 -97 134692 67772 50.32 -98 134696 67776 50.32 -99 134692 67804 50.34 +4 6328 5992 94.69 +5 7008 6744 96.23 +6 7700 7524 97.71 +7 8400 8320 99.05 +8 9116 9092 99.74 +9 9852 9888 100.37 +10 10592 10688 100.91 +11 11352 11496 101.27 +12 12128 12304 101.45 +13 12908 13120 101.64 +14 13716 13924 101.52 +15 14528 14736 101.43 +16 15360 15556 101.28 +17 16204 16368 101.01 +18 17056 17196 100.82 +19 17924 18032 100.60 +20 18808 18868 100.32 +21 19708 19696 99.94 +22 20620 20532 99.57 +23 21544 21372 99.20 +24 22488 22208 98.75 +25 23440 23048 98.33 +26 24400 23888 97.90 +27 25388 24724 97.38 +28 26380 25564 96.91 +29 27388 26408 96.42 +30 28412 27240 95.87 +31 29448 28088 95.38 +32 30500 28928 94.85 +33 31564 29776 94.34 +34 32644 30628 93.82 +35 33732 31488 93.35 +36 34836 32344 92.85 +37 35956 33200 92.34 +38 37088 34060 91.84 +39 38240 34924 91.33 +40 39396 35784 90.83 +41 40568 36652 90.35 +42 41760 37512 89.83 +43 42960 38368 89.31 +44 44184 39232 88.79 +45 45404 40108 88.34 +46 46648 40964 87.82 +47 47904 41832 87.32 +48 49180 42700 86.82 +49 50468 43572 86.34 +50 51764 44428 85.83 +51 53072 45296 85.35 +52 54404 46152 84.83 +53 55744 47020 84.35 +54 57100 47880 83.85 +55 58468 48748 83.38 +56 59844 49616 82.91 +57 61236 50496 82.46 +58 62652 51356 81.97 +59 64080 52220 81.49 +60 65516 53088 81.03 +61 66968 53956 80.57 +62 68428 54832 80.13 +63 69908 55708 79.69 +64 71404 56576 79.23 +65 72904 57460 78.82 +66 74424 58332 78.38 +67 75960 59212 77.95 +68 77508 60088 77.52 +69 79076 60976 77.11 +70 80648 61864 76.71 +71 82236 62744 76.30 +72 83836 63636 75.91 +73 85456 64524 75.51 +74 87088 65396 75.09 +75 88728 66292 74.71 +76 90396 67172 74.31 +77 92064 68072 73.94 +78 93744 68960 73.56 +79 95448 69848 73.18 +80 97164 70740 72.80 +81 98888 71636 72.44 +82 100632 72520 72.06 +83 102392 73404 71.69 +84 104160 74288 71.32 +85 105944 75180 70.96 +86 107736 76064 70.60 +87 109552 76960 70.25 +88 111368 77852 69.91 +89 113204 78752 69.57 +90 115068 79640 69.21 +91 116928 80532 68.87 +92 118808 81420 68.53 +93 120704 82316 68.20 +94 122612 83212 67.87 +95 122728 83312 67.88 +96 122732 83352 67.91 +97 122728 83432 67.98 +98 122728 83428 67.98 +99 122724 83468 68.01 + + diff --git a/examples/multimap_demo_big/multimap_demo_big.ino b/examples/multimap_demo_big/multimap_demo_big.ino new file mode 100644 index 0000000..13454aa --- /dev/null +++ b/examples/multimap_demo_big/multimap_demo_big.ino @@ -0,0 +1,52 @@ +// +// FILE: multimap_demo.ino +// AUTHOR: Rob Tillaart +// PURPOSE: minimal demo +// URL: https://github.com/RobTillaart/MultiMap +// URL: https://forum.arduino.cc/t/messy-math-with-map-and-pow/1275821 +// https://wokwi.com/projects/401812192306752513 + + +#include "MultiMap.h" + +// not the IN array is not equidistant. +// layout is to see the points of the graph. +uint16_t in[300]; +int16_t out[300]; + + +void setup() +{ + // while(!Serial); + Serial.begin(115200); + Serial.println(); + Serial.println(__FILE__); + Serial.print("MULTIMAP_LIB_VERSION: "); + Serial.println(MULTIMAP_LIB_VERSION); + Serial.println(); + + Serial.println("X\tY"); + + for (int i = 0; i < 300; i++) + { + in[i] = i * 3; + out[i] = 32767 * sin(i * 0.1); + } + + + for (int i = 0; i <= 500; i++) + { + int16_t y = multiMap(i, in, out, 300); + Serial.print(i); + Serial.print("\t"); + Serial.println(y * 0.01); // 1 decimal + } +} + + +void loop() +{ +} + + +// -- END OF FILE -- diff --git a/examples/multimap_timing/output_0.3.0.txt b/examples/multimap_timing/output_0.3.0.txt index 5ef900e..58f43c4 100644 --- a/examples/multimap_timing/output_0.3.0.txt +++ b/examples/multimap_timing/output_0.3.0.txt @@ -5,9 +5,10 @@ IDE: 1.8.19 ...Arduino\libraries\MultiMap\examples\multimap_timing\multimap_timing.ino MULTIMAP_LIB_VERSION: 0.3.0 -time : 20 +time : 64 121.0000 -time : 88 +time : 92 121.0909 + done... From a34174dd285f318852736543eafcff4e4c475c3e Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Mon, 23 Feb 2026 22:12:04 +0100 Subject: [PATCH 3/6] fix math overflow --- examples/multimap_demo_big/multimap_demo_big.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/multimap_demo_big/multimap_demo_big.ino b/examples/multimap_demo_big/multimap_demo_big.ino index 13454aa..c8a3216 100644 --- a/examples/multimap_demo_big/multimap_demo_big.ino +++ b/examples/multimap_demo_big/multimap_demo_big.ino @@ -39,7 +39,7 @@ void setup() int16_t y = multiMap(i, in, out, 300); Serial.print(i); Serial.print("\t"); - Serial.println(y * 0.01); // 1 decimal + Serial.println(y * 0.01); } } From 027c6ed4b07ad28801d69c38e13b5aacad57de63 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Mon, 23 Feb 2026 22:13:31 +0100 Subject: [PATCH 4/6] fix math overflow --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e898a98..bfba417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [0.3.0] - 2026-02-23 - fix #13, allow size to be 65535 (uint16_t) -- fix truncating when using int result types (cast to float in math). +- fix math overflow when using int result types. - add multi type **multiMapCache** to have all options. - update readme.md - update GitHub actions From 327fa09e4ede43dd53b25ec074b4a3eb7ad62b80 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Tue, 24 Feb 2026 10:06:59 +0100 Subject: [PATCH 5/6] final edits --- CHANGELOG.md | 4 +- MultiMap.h | 27 ++- README.md | 56 +++-- examples/multimap_2d/multimap_2d.ino | 3 +- examples/multimap_BS_compare/output_0.3.0.txt | 193 +++++++++--------- examples/multimap_demo/multimap_demo.ino | 2 +- .../multimap_demo_big/multimap_demo_big.ino | 13 +- .../multimap_demo_fail/multimap_demo_fail.ino | 55 +++++ 8 files changed, 209 insertions(+), 144 deletions(-) create mode 100644 examples/multimap_demo_fail/multimap_demo_fail.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index bfba417..d21c22c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [0.3.0] - 2026-02-23 - fix #13, allow size to be 65535 (uint16_t) -- fix math overflow when using int result types. -- add multi type **multiMapCache** to have all options. +- add patch for mixed math signed / unsigned multiMap. +- add multi type **multiMapCache** as it was missing. - update readme.md - update GitHub actions - minor edits diff --git a/MultiMap.h b/MultiMap.h index aea7af5..450cdbd 100644 --- a/MultiMap.h +++ b/MultiMap.h @@ -36,7 +36,9 @@ T multiMap(T value, T* _in, T* _out, uint16_t size) if (value == _in[pos]) return _out[pos]; // interpolate in the right segment for the rest - return T(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; + return (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + // if interpolation overflows use this line + // return T(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } @@ -83,7 +85,9 @@ T multiMapCache(T value, T* _in, T* _out, uint16_t size) else { // interpolate in the right segment for the rest - cache = T(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; + cache = (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + // if interpolation overflows use this line + // cache = T(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } } return cache; @@ -114,7 +118,10 @@ T multiMapBS(T value, T* _in, T* _out, uint16_t size) if (value >= _in[mid]) lower = mid; else upper = mid; } - return T(float(value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower])) + _out[lower]; + // interpolate in the right segment for the rest + return (value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower]) + _out[lower]; + // if interpolation overflows use this line + // return T(float(value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower])) + _out[lower]; } @@ -138,7 +145,9 @@ T2 multiMap(T1 value, T1* _in, T2* _out, uint16_t size) if (value == _in[pos]) return _out[pos]; // interpolate in the right segment for the rest - return T2(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; + return (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + // if interpolation overflows use this line + // return T2(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } @@ -185,7 +194,9 @@ T2 multiMapCache(T1 value, T1* _in, T2* _out, uint16_t size) else { // interpolate in the right segment for the rest - cache = T2(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; + cache = (value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1]; + // if interpolation overflows use this line + // return T2(float(value - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1])) + _out[pos-1]; } } return cache; @@ -215,8 +226,10 @@ T2 multiMapBS(T1 value, T1* _in, T2* _out, uint16_t size) if (value >= _in[mid]) lower = mid; else upper = mid; } - - return T2(float(value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower])) + _out[lower]; + // interpolate in the right segment for the rest + return (value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower]) + _out[lower]; + // if interpolation overflows use this line + // return T2(float(value - _in[lower]) * (_out[upper] - _out[lower]) / (_in[upper] - _in[lower])) + _out[lower]; } diff --git a/README.md b/README.md index 30032df..981c065 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,26 @@ However there might be more than one input value mapping onto the same output va See - https://en.wikipedia.org/wiki/Bijection,_injection_and_surjection +### Math problems in interpolation (rare). + +In multiMap the interpolation math can fail. This happens when integer types are used +that are too small to handle the multiplication in the interpolation (e.g. 8 or 16 bit) +Also when a mixed signed / unsigned types are used this can happen. + +There are two solutions to handle this. +- (preferred) use float (double) as either input or output type. +This forces casting to float in the interpolation solving the math problem. +Drawback is it might take extra memory (e.g. int16_t => float). +- The multiMap.h file contains **commented** code to cast the interpolation +during the interpolation only. +Comment the existing interpolation and uncomment the other line. +This saves memory as the arrays used do not "grow". + +Note both solutions have a performance penalty + +See the sketch **multimap_demo_fail.ino** (UNO R3) to show the problem. + + ### 0.3.0 Breaking change This 0.3.0 version makes the previous versions obsolete. @@ -64,35 +84,13 @@ This 0.3.0 version makes the previous versions obsolete. Since 0.3.0 sizes of multiMap can exceed 256 elements, up to 65535 elements. This is because the size has changed from an uint8_t => uint16_t. -More important the internal math has an extra float cast as when using int types -there was sometimes an overflow in the interpolation (rare but wrong). - -On an UNO R3 this breaking change altered the performance. -Linear search got better, binary search got worse but is still -better than the linear search. - -From **multimap_BS_compare.ino** version 0.2.1 versus 0.3.0. - -| version | size | t1 | t2 | ratio | -|:----------|:------:|--------:|--------:|----------:| -| 0.2.1 | 10 | 9476 | 9364 | 98.82 | -| 0.2.1 | 15 | 13348 | 12628 | 94.61 | -| 0.2.1 | 20 | 17808 | 15948 | 89.56 | -| 0.2.1 | 30 | 28476 | 22712 | 79.76 | -| 0.2.1 | 40 | 41516 | 29620 | 71.35 | -| 0.2.1 | 50 | 56896 | 36608 | 64.34 | -| 0.2.1 | 70 | 94716 | 50700 | 53.53 | -| 0.2.1 | 90 | 141936 | 65136 | 45.89 | -| | | | | | -| 0.3.0 | 10 | 10592 | 10688 | 100.91 | -| 0.3.0 | 15 | 14528 | 14736 | 101.43 | -| 0.3.0 | 20 | 18808 | 18868 | 100.32 | -| 0.3.0 | 30 | 28412 | 27240 | 95.87 | -| 0.3.0 | 40 | 39396 | 35784 | 90.83 | -| 0.3.0 | 50 | 51764 | 44428 | 85.83 | -| 0.3.0 | 70 | 80648 | 61864 | 76.71 | -| 0.3.0 | 90 | 115068 | 79640 | 69.21 | -| | | | | | +On an UNO R3 the change of the size to uint16_t altered the performance. +Linear search got better, binary search got worse but still performs +better than the linear search in a test. + +Run **multimap_BS_compare.ino** to see the differences. + +(output logs of UNO R3 are in the example folder). ### Related diff --git a/examples/multimap_2d/multimap_2d.ino b/examples/multimap_2d/multimap_2d.ino index 05e4c46..c03e05d 100644 --- a/examples/multimap_2d/multimap_2d.ino +++ b/examples/multimap_2d/multimap_2d.ino @@ -4,9 +4,10 @@ // PURPOSE: demo mapping an angle on a semi-circle (2D {x, y} position) // URL: https://github.com/RobTillaart/MultiMap // -// when printing into a plotter one sees a rough sine and cosine +// when printing into a plotter one sees a very rough sine and cosine // with an amplitude of 5, approximated with interpolation. + #include "MultiMap.h" float in[] = { 0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330, 360 }; diff --git a/examples/multimap_BS_compare/output_0.3.0.txt b/examples/multimap_BS_compare/output_0.3.0.txt index cf745f5..538b7e9 100644 --- a/examples/multimap_BS_compare/output_0.3.0.txt +++ b/examples/multimap_BS_compare/output_0.3.0.txt @@ -6,102 +6,103 @@ Arduino\libraries\MultiMap\examples\multimap_BS_compare\multimap_BS_compare.ino MULTIMAP_LIB_VERSION: 0.3.0 size t1 t2 ratio -4 6328 5992 94.69 -5 7008 6744 96.23 -6 7700 7524 97.71 -7 8400 8320 99.05 -8 9116 9092 99.74 -9 9852 9888 100.37 -10 10592 10688 100.91 -11 11352 11496 101.27 -12 12128 12304 101.45 -13 12908 13120 101.64 -14 13716 13924 101.52 -15 14528 14736 101.43 -16 15360 15556 101.28 -17 16204 16368 101.01 -18 17056 17196 100.82 -19 17924 18032 100.60 -20 18808 18868 100.32 -21 19708 19696 99.94 -22 20620 20532 99.57 -23 21544 21372 99.20 -24 22488 22208 98.75 -25 23440 23048 98.33 -26 24400 23888 97.90 -27 25388 24724 97.38 -28 26380 25564 96.91 -29 27388 26408 96.42 -30 28412 27240 95.87 -31 29448 28088 95.38 -32 30500 28928 94.85 -33 31564 29776 94.34 -34 32644 30628 93.82 -35 33732 31488 93.35 -36 34836 32344 92.85 -37 35956 33200 92.34 -38 37088 34060 91.84 -39 38240 34924 91.33 -40 39396 35784 90.83 -41 40568 36652 90.35 -42 41760 37512 89.83 -43 42960 38368 89.31 -44 44184 39232 88.79 -45 45404 40108 88.34 -46 46648 40964 87.82 -47 47904 41832 87.32 -48 49180 42700 86.82 -49 50468 43572 86.34 -50 51764 44428 85.83 -51 53072 45296 85.35 -52 54404 46152 84.83 -53 55744 47020 84.35 -54 57100 47880 83.85 -55 58468 48748 83.38 -56 59844 49616 82.91 -57 61236 50496 82.46 -58 62652 51356 81.97 -59 64080 52220 81.49 -60 65516 53088 81.03 -61 66968 53956 80.57 -62 68428 54832 80.13 -63 69908 55708 79.69 -64 71404 56576 79.23 -65 72904 57460 78.82 -66 74424 58332 78.38 -67 75960 59212 77.95 -68 77508 60088 77.52 -69 79076 60976 77.11 -70 80648 61864 76.71 -71 82236 62744 76.30 -72 83836 63636 75.91 -73 85456 64524 75.51 -74 87088 65396 75.09 -75 88728 66292 74.71 -76 90396 67172 74.31 -77 92064 68072 73.94 -78 93744 68960 73.56 -79 95448 69848 73.18 -80 97164 70740 72.80 -81 98888 71636 72.44 -82 100632 72520 72.06 -83 102392 73404 71.69 -84 104160 74288 71.32 -85 105944 75180 70.96 -86 107736 76064 70.60 -87 109552 76960 70.25 -88 111368 77852 69.91 -89 113204 78752 69.57 -90 115068 79640 69.21 -91 116928 80532 68.87 -92 118808 81420 68.53 -93 120704 82316 68.20 -94 122612 83212 67.87 -95 122728 83312 67.88 -96 122732 83352 67.91 -97 122728 83432 67.98 -98 122728 83428 67.98 -99 122724 83468 68.01 +4 5588 5600 100.21 +5 6160 6200 100.65 +6 6756 6820 100.95 +7 7368 7448 101.09 +8 7992 8076 101.05 +9 8636 8700 100.74 +10 9308 9344 100.39 +11 9996 9996 100.00 +12 10700 10644 99.48 +13 11424 11288 98.81 +14 12172 11944 98.13 +15 12936 12588 97.31 +16 13724 13232 96.42 +17 14524 13884 95.59 +18 15348 14552 94.81 +19 16192 15224 94.02 +20 17052 15892 93.20 +21 17936 16564 92.35 +22 18836 17232 91.48 +23 19748 17904 90.66 +24 20688 18580 89.81 +25 21648 19252 88.93 +26 22624 19928 88.08 +27 23620 20592 87.18 +28 24644 21260 86.27 +29 25680 21936 85.42 +30 26728 22608 84.59 +31 27804 23276 83.71 +32 28896 23952 82.89 +33 30008 24628 82.07 +34 31140 25320 81.31 +35 32296 26008 80.53 +36 33464 26700 79.79 +37 34652 27396 79.06 +38 35864 28088 78.32 +39 37096 28780 77.58 +40 38340 29476 76.88 +41 39612 30164 76.15 +42 40900 30860 75.45 +43 42204 31556 74.77 +44 43532 32252 74.09 +45 44880 32944 73.40 +46 46244 33640 72.74 +47 47624 34336 72.10 +48 49032 35028 71.44 +49 50452 35724 70.81 +50 51900 36420 70.17 +51 53356 37108 69.55 +52 54844 37804 68.93 +53 56340 38500 68.34 +54 57856 39196 67.75 +55 59400 39888 67.15 +56 60960 40580 66.57 +57 62536 41276 66.00 +58 64136 41972 65.44 +59 65748 42668 64.90 +60 67388 43360 64.34 +61 69044 44056 63.81 +62 70716 44756 63.29 +63 72412 45448 62.76 +64 74128 46144 62.25 +65 75856 46840 61.75 +66 77608 47552 61.27 +67 79384 48268 60.80 +68 81176 48976 60.33 +69 82980 49696 59.89 +70 84812 50408 59.43 +71 86656 51128 59.00 +72 88528 51844 58.56 +73 90416 52556 58.13 +74 92320 53276 57.71 +75 94248 53992 57.29 +76 96196 54704 56.87 +77 98156 55428 56.47 +78 100148 56132 56.05 +79 102144 56860 55.67 +80 104176 57572 55.26 +81 106220 58292 54.88 +82 108280 59008 54.50 +83 110360 59716 54.11 +84 112460 60436 53.74 +85 114580 61156 53.37 +86 116720 61872 53.01 +87 118876 62588 52.65 +88 121056 63304 52.29 +89 123252 64020 51.94 +90 125468 64736 51.60 +91 127700 65456 51.26 +92 129960 66172 50.92 +93 132236 66896 50.59 +94 134528 67608 50.26 +95 134696 67696 50.26 +96 134696 67724 50.28 +97 134692 67772 50.32 +98 134696 67776 50.32 +99 134692 67804 50.34 + diff --git a/examples/multimap_demo/multimap_demo.ino b/examples/multimap_demo/multimap_demo.ino index fa2c3be..7f7e08e 100644 --- a/examples/multimap_demo/multimap_demo.ino +++ b/examples/multimap_demo/multimap_demo.ino @@ -9,7 +9,7 @@ #include "MultiMap.h" -// not the IN array is not equidistant. +// note the IN array is not equidistant. // layout is to see the points of the graph. float in[] = { 0, 20, 40, 50, 60, 80, 90, 100, 105 }; float out[] = { 1, 2.8, 4.5, 7.0, 10.4, 33.5, 57.5, 100, 120 }; diff --git a/examples/multimap_demo_big/multimap_demo_big.ino b/examples/multimap_demo_big/multimap_demo_big.ino index c8a3216..bc5f87a 100644 --- a/examples/multimap_demo_big/multimap_demo_big.ino +++ b/examples/multimap_demo_big/multimap_demo_big.ino @@ -1,17 +1,15 @@ // -// FILE: multimap_demo.ino +// FILE: multimap_demo_big.ino // AUTHOR: Rob Tillaart // PURPOSE: minimal demo // URL: https://github.com/RobTillaart/MultiMap -// URL: https://forum.arduino.cc/t/messy-math-with-map-and-pow/1275821 -// https://wokwi.com/projects/401812192306752513 +// #include "MultiMap.h" -// not the IN array is not equidistant. -// layout is to see the points of the graph. -uint16_t in[300]; +// both are signed. +int16_t in[300]; int16_t out[300]; @@ -33,10 +31,9 @@ void setup() out[i] = 32767 * sin(i * 0.1); } - for (int i = 0; i <= 500; i++) { - int16_t y = multiMap(i, in, out, 300); + int16_t y = multiMap(i, in, out, 300); Serial.print(i); Serial.print("\t"); Serial.println(y * 0.01); diff --git a/examples/multimap_demo_fail/multimap_demo_fail.ino b/examples/multimap_demo_fail/multimap_demo_fail.ino new file mode 100644 index 0000000..ea9828d --- /dev/null +++ b/examples/multimap_demo_fail/multimap_demo_fail.ino @@ -0,0 +1,55 @@ +// +// FILE: multimap_demo_fail.ino +// AUTHOR: Rob Tillaart +// PURPOSE: minimal demo +// URL: https://github.com/RobTillaart/MultiMap +// +// compare to multimap_demo_big.ino. +// +// View this demo on the serial plotter how it fails (at least on UNO R3) +// due to a mix of signed and unsigned math. +// If you need this mapping and it fails for you +// the interpolation in MultiMap.h needs the casting line. + + +#include "MultiMap.h" + +// note mixed signs +uint16_t in[300]; +int16_t out[300]; + + +void setup() +{ + // while(!Serial); + Serial.begin(115200); + Serial.println(); + Serial.println(__FILE__); + Serial.print("MULTIMAP_LIB_VERSION: "); + Serial.println(MULTIMAP_LIB_VERSION); + Serial.println(); + + Serial.println("X\tY"); + + for (int i = 0; i < 300; i++) + { + in[i] = i * 3; + out[i] = 32767 * sin(i * 0.1); + } + + for (int i = 0; i <= 500; i++) + { + int16_t y = multiMap(i, in, out, 300); + Serial.print(i); + Serial.print("\t"); + Serial.println(y * 0.01); + } +} + + +void loop() +{ +} + + +// -- END OF FILE -- From 655d8c936da9e0b120850ea218b797bae1ca11fc Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Tue, 24 Feb 2026 10:19:01 +0100 Subject: [PATCH 6/6] final edits --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d21c22c..dc10fc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [0.3.0] - 2026-02-23 - fix #13, allow size to be 65535 (uint16_t) -- add patch for mixed math signed / unsigned multiMap. +- add patch for possible interpolation under/overflows. - add multi type **multiMapCache** as it was missing. - update readme.md - update GitHub actions