I was thinking how fun it would be to save hour min sec in a two byte integer which normally is impossible because there are 86400 in a day and unsigned integer has only 65536 possible values. but what if I simply map the range, to the possible values, some degree of precision will be lost but that is not important. Well here's what I got using this code.
long UTCHour = 18;
long UTCMinute = 59;
long UTCSecond = 35;
long in;
long out;
void setup() {
Serial.begin(115200);
delay(8000); //allow serial to start lest some stuff become missing.
}
void loop() {
Serial.println("Start ");
Serial.print(" in UTCHour "); Serial.println(UTCHour);
Serial.print(" in UTCMinute "); Serial.println(UTCMinute);
Serial.print(" in UTCSecond "); Serial.println(UTCSecond);
in = (UTCHour * 60 * 60) + (UTCMinute * 60) + UTCSecond;//total seconds
Serial.print("total seconds in "); Serial.println(in);
out = map( in, 0, 86400, 0, 65535); //fit to a 2 byte integer
Serial.print("after map 1 "); Serial.println(out);
out = map(out, 0, 65535, 0, 86400); //expand back to original
Serial.print("after map 2 "); Serial.println(out);
UTCHour = out / 3600;
Serial.print("out UTCHour "); Serial.println(UTCHour);
out = out - (UTCHour * 3600);
UTCMinute = out / 60;
Serial.print("out UTCMinute "); Serial.println(UTCMinute);
UTCSecond = out - (UTCMinute * 60);
Serial.print("out UTCSecond "); Serial.println(UTCSecond);
Serial.println();
UTCHour = random(24); UTCMinute = random(60); UTCSecond = random(60);
delay(8000);
}
but here's the output, the first is perfect I get the same thing I put in, but not in the second one. What am I doing wrong. I think it must have to do with the signed unsigned thing but with long there are enough positive numbers to handle this I would think.
Start
in UTCHour 5
in UTCMinute 44
in UTCSecond 48
total seconds in 20688
after map 1 15692
after map 2 20688
out UTCHour 5
out UTCMinute 44
out UTCSecond 48
Start
in UTCHour 10
in UTCMinute 34
in UTCSecond 32
total seconds in 38072
after map 1 -20831
after map 2 -27462
out UTCHour -7
out UTCMinute -37
out UTCSecond -42
Thanks. I put that code in my own function, and placed the OP's test in the wokwi for convenince.
If map() is your problem, which it may well be, lose all the clutter and boil it down for experimentation.
void loop() {
in = 20000;
Serial.print("total seconds in ");
Serial.println(in);
out = map( in, 0, 86400, 0, 65535);
Serial.print("after map 1 ");
Serial.println(out);
out = map(out, 0, 65535, 0, 86400);
Serial.print("after map 2 ");
Serial.println(out);
for (;;); // or just put the code in setup();
}
you can just edit and restart the code, makes it painless and perhaps obvious.
On the other hand, why not just divide the number of seconds by two, you'll get a loss of precision, natch, but a consistent and maybe acceptable result. Give anyone who notices the seconds are always even for a second a cookie.
yes, with long long anything seems to work to wit:
Start
in UTCHour 160
in UTCMinute 35
in UTCSecond 45
total seconds in 578145
step1 578145
step2 65535
step3 37888732575
step4 86400
step5 86400
step6 438526
after map 1 438526
step1 438526
step2 86400
step3 37888646400
step4 65535
step5 65535
step6 578143
after map 2 578143
out UTCHour 160
out UTCMinute 35
out UTCSecond 43
obviously eventually it will break, but this is good enough for now. Methinks the documentation should be very explicit in pointing out the pitfalls of the published function because while nothing I do is life or death, this could wind up in an airplane autopilot, or power plant, or manufacturing process and survive testing long enough to go into production and oops, somebody died.
I agree. Although I certainly hope no Arduinos are any part of, say, the Boeing 737 Max's Maneuvering Characteristics Augmentation System... and that testing would at least find a problem like yours where it clearly doesn't work after a certain TOD.
But I did see
Longtime Boeing engineers say the effort was complicated by a push to outsource work to lower-paid contractors.
$9 an hour. Cough!
After some other kinds of "excitement" with the map() function I don't use it.
You can see from the code that it is a simple enough function; there are ppl who could just look at it and predict where (and how) it will fail. I suppose the documentation don't go into that because, well, it is inexcusable, truly, life threats in the picture or not. Look at how much time you and we wasted spent on it!
One thing that surprised me was the point @TomGeorge raised - the equations that inform the result will cheerfully extrapolate and return values no matter where the input is with respect to the input range. Hence his advice to keep the constrain() function in mind.
Another place it does not satisfy is mapping from or to a very small set of values. Not all numbers get equal treatment - the high return value might obtain in only one case among many, or something like that: I've forgotten more than I ever knew about it and have not (until this day!) looked back.