in my recent project I need to store a huge numbers that are much bigger than 32bit integer. Just storing them could be possible as a byte array (I guess). But I also need some basic arythmetic operations with them - in my case multiplications.
Here is my code (simplified):
int senseValue = 8123456; //this value changes up to decades of millions, but fits in 32bit integer
int pow3 = pow(senseValue,3); //this cant fit 32 bit integer :(
double constant = 0.000000000034;
double result = pow3* constant;
Serial.print("\nCONVERTED VALUE: ");
Serial.print(result);
Is there some effective way to do such operations? I am sure it could be done in byte level calculations, but it would be quite complicated and complete work from scratch.
int64_t and uint64_t do work but are performance killers in my experience,
if you need them use them only for the part where the math is actually 64 bit.
As soon as 32 bit or even 16 bit is enough switch to smaller datatypes.
(but only if performance is an issue)
Another option could be the Big Number Library ported by Nick Gammon
robtillaart:
int64_t and uint64_t do work but are performance killers in my experience,
if you need them use them only for the part where the math is actually 64 bit.
As soon as 32 bit or even 16 bit is enough switch to smaller datatypes.
(but only if performance is an issue)
Another option could be the Big Number Library ported by Nick Gammon
When time is on my side I might add it to the big number library someday
I just read it through. Most interesting. Random big numbers would go well in the Big Numbers Library.
(I don't know if I'll personally ever need anything larger than 32-bit, but the subject still appeals to me.)
in my recent project I need to store a huge numbers that are much bigger than 32bit integer. Just storing them could be possible as a byte array (I guess). But I also need some basic arythmetic operations with them - in my case multiplications.
Here is my code (simplified):
int senseValue = 8123456; //this value changes up to decades of millions, but fits in 32bit integer
int pow3 = pow(senseValue,3); //this cant fit 32 bit integer
double constant = 0.000000000034;
double result = pow3* constant;
Is there some effective way to do such operations? I am sure it could be done in byte level calculations, but it would be quite complicated and complete work from scratch.
Thanks for any advice.
Use a float (or, if you have a Due, a double) for pow3.
Either that, or use algebra:
0.000000000034*pow(x,3) is approximately pow((x/3087),3)
If size is your problem and not precision (which I guess because your constant appears to have only two significant digits), you can get results with 32 bit arithmetic and scaling. I also guess that you want an integer result, so I wrote a demo to show how you can do the calculations using standard functions in 32 bit precision, and store the result in a 64 bit integer.
In the end, the demo can't print the result because println() can't print long longs. So I just scaled it down to prove that the 64 bit result contains the correct value.
// scaling is everything :)
// aarg in the arduino forum 2015-11-21
void setup() {
Serial.begin(9600);
// problem code:
long senseValue = 8123456; //this value changes up to decades of millions, but fits in 32bit integer
int pow3 = pow(senseValue,3); //this cant fit 32 bit integer :(
double constant = 0.000000000034;
double result = pow3* constant;
Serial.println("Actual value: 18226421713.061812895744");
Serial.println("INCORRECTLY CONVERTED VALUE: ");
Serial.println(result);
// That didn't work.
// So we can scale the values to solve
// and put the result in a 64 bit integer:
//
float calcValue = senseValue / 1000000.0;
float pow3_scaled = pow(calcValue,3); //this now fits a 32 bit float :)
float result_scaled = pow3_scaled * 34000.0;
long long final_result = result_scaled * 1000; // final result now contains a correctly scaled result in a 64 bit integer
// but println can't handle long longs, so we have to scale it down again for proof:
long printable_result = final_result / 1000;
Serial.println("Actual value: 18226421713.061812895744");
Serial.println("Scaled and correctly calculated value / 1000: ");
Serial.println(printable_result);
}
void loop() {}
Thank you all guys for outstanding in-depth answers!
Big Numbers library is probably the best solution at a time.
But problem is that I need to do few such calculations per second and need to stay synchronized with high speed UART connection (250kbps). I will use this library anyway, but not for these calculations because of power requirements.
But I found another solution during the night when I was thinking about sort of mathematical simplification of square root(s) of big numbers.
My idea come from knowing that my calculation is alway like this:
result = (bignumber)^2 * smallconstant
or:
result = (bignumber)^3 * smallconstant
for example:
result = (3762)^2 * 0,001 //result is 14152,644
is equal to:
result = (3,762^2) * (1000^2) * (SQRT(0,001))
(1) (2) (3)
So if I force Arduino to multiply first(1) and last(3) number at first, result is still in double resolution. In the final multiplication with middle(2) number I am again still in double resolution
Tried this calculation with bigger numbers (about million as bignumber and constant is always like 0,00003 or less).
Getting these old knowledge from math is always a pain
Helium328PU:
But problem is that I need to do few such calculations per second and need to stay synchronized with high speed UART connection (250kbps).
No, problem is that master 250kbps UART device has multiple slave devices connected, and they are synchronized by proprietary software.
Arduino acts here as slave (only) reader, and because I cannot regulate data flow / data requests (pause/stop), it is crucial to stay in synchronization.
in my recent project I need to store a huge numbers that are much bigger than 32bit integer. Just storing them could be possible as a byte array (I guess). But I also need some basic arythmetic operations with them - in my case multiplications.
What are you really trying to do? These calculations are a means to an end-- what is the end?
Also, a float can go to up to about 3.41038.
Here is a link for you to look at: IEEE-754 Floating Point Converter
It's just that the Arduino print library craps out at about 4.3109. For numbers bigger than this, it will tell you ovf but that is a lie.
odometer:
What are you really trying to do? These calculations are a means to an end-- what is the end?
Well only important thing about "the end" is that I need to print these values on multiple serial ports and eventually store them on external memory modules. These calculations are only a small problematic part of a really complex project.
odometer:
Also, a float can go to up to about 3.41038.
Here is a link for you to look at: IEEE-754 Floating Point Converter
It's just that the Arduino print library craps out at about 4.3109. For numbers bigger than this, it will tell you ovf but that is a lie.
Thanks, this is very usable. I first noticed problems with ovf from serial, but thought that it was problem with out of range number rather than serial issue
Anyway, I solved this in post #10 with changing the equation. But it is solution only in this case. Other cases should use bignumber library or other mentioned solutions.
Helium328PU:
Well only important thing about "the end" is that I need to print these values on multiple serial ports and eventually store them on external memory modules. These calculations are only a small problematic part of a really complex project.