-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Greatly reduced error rate of WMath map() roundtrip #309
base: master
Are you sure you want to change the base?
Conversation
Here's the sketch to prove: uint32_t expired;
uint32_t iterations;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println("check map");
expired = 0;
iterations = 0;
}
constexpr int imin = 0;
constexpr int imax = 180;
constexpr int omin = 1000;
constexpr int omax = 2000;
int i = 0;
int fails = 0;
void loop()
{
++iterations;
i = (i + 1) % (imax + 1);
#if defined(ESP8266) || defined(ESP32)
cli();
volatile auto start = ESP.getCycleCount();
#else
// Set Timer 1 to normal mode at F_CPU.
TCCR1A = 0;
TCCR1B = 1;
cli();
volatile uint16_t start = TCNT1;
#endif
volatile auto o = map(i, imin, imax, omin, omax);
#if defined(ESP8266) || defined(ESP32)
sei();
volatile auto cycles = ESP.getCycleCount() - start;
#else
sei();
volatile uint16_t finish = TCNT1;
uint16_t cycles = finish - start;
#endif
expired += cycles;
if (i != map(o, omin, omax, imin, imax))
{
++fails;
}
if (iterations > 100000)
{
Serial.print("Cycles per map(...) = "); Serial.print(expired / iterations);
Serial.print(", fails = "); Serial.print(fails);
Serial.println();
expired = 0;
iterations = 0;
fails = 0;
}
} |
maybe a duplicate of this? |
@PaulStoffregen Well, hardly - this is a PR fixing smth tangible - rounding to the nearest integer instead of down -, the other is an issue griping about this and that evilgrin |
Here's a more comprehensive answer :-)
This solves for result, given x where in_min <= x <=in_max: I consider comparable performance to the existing |
One month ago, I commented on the several other map() issues. It seems nobody really cares about map(). For Teensy's core library, we're moving to a slower but (hopefully) perfectly accurate version of map() where the integer version gives the same result if done with floating point using proper round-off, and where floating point is used if the input being mapped is a float. I shared the code and a test program on the other issue and also on the Arduino forum. As to what I think, your code looks better than what Arduino is currently using. So do most of the proposals. My hunch is your round off might end up going the wrong direction when "divisor" and "dividend" aren't the same sign. But I wrote that test program to explore those sorts of issues. Best to actually test... Whether some small error or improper round off is acceptable for certain cases in exchange for better speed is a judgement call each core library maintainer needs to make. Or not. Just keeping the same ancient code which gives correct results at the extremes but terrible distribution between seems to be the path Arduino will always take regardless of how many better alternative are proposed. Unless there is some sign of genuine interest, I'm done here. I've shared all of my work on map(). |
Dit you ever test it carefully? So you really ask yourself why your "improved" code was not accepted? |
Please close this PR |
… ranges) for round-trip mapping at the same performance. (Based on "improved_map" from ESP8266's Servo.cpp)
c265ddb is a trivial rebase to current master. |
@PaulStoffregen In response to your remarks about signedness I added a comment to express the expectation that the function does not expect limit1, limit2 like range delimiters, but that min < max, or at the least, min <= max.
is the result of an undefined use. That said, I don't see which algebraic rules allow, effectively |
Certainly not warranted, at least based on your conjecture. |
@dok-net You are right, I corrected my remark. |
@ArminJo So now you've created another synthetic set of internal values without giving proper values for the whole function's input. Guessing your intentions, anyway, and ignoring that min < max by definition, lets compare the implementation in master:
which gives us |
Half, or zero errors, depending on in/out…… ranges, for round-trip mapping at the same performance.
(Based on "improved_map" from ESP8266's Servo.cpp)