I need to process a large number (specifically, an epoch time expressed in milliseconds). It's coming in to my board as JSON. Best I can figure, when I parse it out as a JSON object it's being treated as a double. But because it's so big, I cannot get an accurate value. I need seconds resolution, not milliseconds, so I'm okay with truncating, but I can't even get that to to work. In theory, a double or an unsigned long should be large enough to hold the value in seconds, but nothing is big enough for millis.
The code below is the closest I've gotten, but it is weirdly off.
For most Arduino controllers, a double is a float, which means 4 bytes for storage, or roughly 3.4E+/-38. However, the number of significant digits (e.g., precision) is 6 or 7 digits. So while it could print out a number with 38 digits, only the first 6 or 7 mean anything. Everything after that is about the same as a random guess. My guess is you're not going to get the resolution you need.
I may just have to figure out how to truncate it in the raw json string before processing it. Did a quick experiment and the 10 digit epoch time (seconds) seems to be handled fine as a u-long with this code.
Hmm, is there a way I can pull it from the json as string/char * rather than a double (without adding quotes to the string)? That would simplify my life.
is there a way I can pull it from the json as string/char * rather than a double
Use the functions atol() or strtoul() to convert digits in a zero-terminated character array (c-string) to unsigned long. That way you get about 10 decimal digits.
That's the opposite of what I need. The JSON library returns it from the JSON doc as a double (because it's not in quotes, and I don't control that). At that point, the "damage" is already done. What I want is for the JSON library to treat it as a c-string to begin with. THEN I can start doing something like the above.
To that end I've started writing some pre-processing to throw the quotes around the values before processing it as JSON. It's ugly but I think it will work.
jremington:
The Uno does not support the double data type.
Sort of. You can type as a double, but it's no different than a float. The object coming back from the JSON library is typed as a "double" so I'm just calling it that for consistency. I'm aware it's just a float.
You get 6-7 decimal digits with a float, period, regardless of whether the AVR-gcc compiler allows you to type "double" instead of float. The decision to allow that was an incredibly bad one.
If you want to convert an ASCII string of 10 decimal digits to binary or vice versa on an Uno, your best option is unsigned long integers. That is fine for milliseconds, for up to 57 days.
Edit: Not useful for converting your example ASCII constant, though:
unsigned long x=strtoul("1559885523000",NULL,10); //x is assigned 4294967294
This is the epoch in milliseconds: https://currentmillis.com/
It is now: "1559951564946". The Arduino can not handle that, but if the three lowest digits are stripped to get the seconds, then you get "1559951564" and that is a normal 32-bit unsigned long number.
For your "1559885523000.0", remove the ".0" and remove the three lowest digits. Then convert the "1559885523" with strtoul() as jremington wrote. Then you have the epoch time.
I don't know how to use the JSON library to get that as a string. If you have that as a string, then you can strip those digits yourself before converting.
Do not try to put that into a floating point variable.
The ESP32, which can be programmed in the Arduino IDE after installing their patch, has some data that types are different than the Arduino family. It appears to support 4-byte floats and 8-byte doubles. I ran this program:
void setup() {
float x;
double y;
Serial.begin(115200);
while (Serial.available());
Serial.print("Size of a float is ");
Serial.println(sizeof(float));
Serial.print("Size of a double is ");
Serial.println(sizeof(double));
}
void loop() {
}
And it displays:
Size of a float is 4 Size of a double is 8
I ran the test on the HiLetgo ESP32-WROOM-32 board. It has over 1Mb of flash, 350Kb of SRAM, built-in Wifi and Bluetooth, and scoots along at 240MHz, all for about $15.