BigNumber - a practical issue

I have quite a practical need to use the BigNumber library finally.
I need to calculate this simple formula:

// BigNumber library
#include "BigNumber.h"

void setup() {   

	Serial.begin(115200);  

        BigNumber::begin ();  // initialize the library
	
        BigNumber result;

	unsigned long a, b;
	unsigned int c, d;  // or unsigned long
	double e;

	// an example of typical values (these values are not constants, 
        // they come from an external measurement system):
	
	a = 23948398;
	b = 8380334;

	c = 135;
	d = 12032;

	e = 0.72348;

	// the actual formula:
	
	result = (a * b) / (c * 65536 + d + e);

        // the result = 22653423.351809387532795061757447

	Serial.println(result);
}

void loop() {
};

It compiles, gives 0 (or, when playing with types/castings - compile errors or results ignoring some variables values).
I've tried to use these libs, with all possible variations of operand's types, splitting the formula, etc.

http://forum.arduino.cc/index.php/topic,85692.0.html
Any hint how to do it??
Thanks!

It compiles, gives 0.

Of course it does. The type that the result is to be stored in matters ONLY when the result is to be stored. Until then, the type of the value to be stored is that of the largest type in the expression. Since the largest type in the expression is float, the value will be 4 bytes. And, since a and b are longs, a * b will be long, too.

Casting is needed, OR make one or more of the variables involved BigNumber.

I did my best with various castings, splittings, reordering..
If somebody may show me the actual mod of the above code giving the correct result I would be very :slight_smile:

pito:
I did my best with various castings..
If somebody may show me the actual mod of the above code giving the correct result I would be :slight_smile:

But you didn't think to make the operands the same type as the result?

I did.. For example (added the printBigNum() ):

// BigNumber library
#include "BigNumber.h"

void setup() {   

	Serial.begin(115200);  

	BigNumber::begin();  // initialize library
	BigNumber result, ab, bb, cb, db, eb;

	unsigned long a, b;
	unsigned int c, d;  // or unsigned long
	double e;

	// an example of typical values:

	a = 23948398;
	b = 8380334;

	c = 7883;
	d = 12032;

	e = 0.72348;

	ab = a;
	bb = b;
	cb = c;
	db = d;
	eb = e;

	// the actual formula:

	result = (ab * bb) / (cb * 65536 + db + eb);

	Serial.println(result);
	printBigNum(result);
}

void loop() {
};


//function to display a big number and free it afterwards
//modified println to print
void printBigNum (BigNumber n)
{
	char * s = n.toString ();
	Serial.print (s);
	free (s);
}  // end of printBignum

It does not compile, overloading issues:

D:\MyCode\Arduino\BigNumber_test\BigNumber_test.ino: In function 'void setup()':
D:\MyCode\Arduino\BigNumber_test\BigNumber_test.ino:35: error: ambiguous overload for 'operator*' in 'cb * 65536l'
D:\MyCode\Arduino\BigNumber_test\BigNumber_test.ino:35: note: candidates are: operator*(long int, long int) <built-in>
D:\MyCode\Arduino\libraries\BigNumber/BigNumber.h:67: note:                 BigNumber BigNumber::operator*(const BigNumber&) const
Failed compiling sketch
	ab = a;
	bb = b;
	cb = c;
	db = d;
	eb = e;

	// the actual formula:

	result = (a * b) / (c * 65536 + d + e);

The calculation does not depend on any BigNumber variables, so the fact that the result is the same is no surprise.

cut and paste issue - see above corrected results..

cb * 65536

Which version of the * operator should the compiler use? It's telling you that it can't choose for you. You must tell it, by making 65536 a BigNumber variable, or by using a cast.

Clear:

// BigNumber library
#include "BigNumber.h"

void setup() {   

	Serial.begin(115200);  

	BigNumber::begin();  // initialize library

	BigNumber result, ab, bb, cb, db, eb, to16;

	unsigned long a, b;
	unsigned int c, d;  // or unsigned long
	double e;

	to16 = "65536";

	// an example of typical values:

	a = 23948398;
	b = 8380334;

	c = 7883;
	d = 12032;

	e = 0.72348;

	ab = a;
	bb = b;
	cb = c;
	db = d;
	eb = e;

	// the actual formula:

	result = (ab * bb) / (cb * to16 + db + eb);

	Serial.println(result);
	printBigNum(result);
}

void loop() {
};


//function to display a big number and free it afterwards
//modified println to print
void printBigNum (BigNumber n)
{
	char * s = n.toString ();
	Serial.print (s);
	free (s);
}  // end of printBignum

Result:
0
0

And so on..

Instead of computing the whole equation in one step, break it into intermediate steps. What is ab * bb? What is cb * to16? What is that value + db? What is that value + eb?

What is the result of the division?

And, where is Nick?

Paul, I did all that in past (see my first post). Spent days..
It seems we need somebody from Bletchley Park to help :slight_smile:
Or Nick's advise, of course..

Paul, I did all that in past (see my first post). Spent days..

But, you can't spend 5 more minutes?

BigNumber t1 = ab * bb;
printBigNum(t1);

BigNumber t2 = cb + to16;
printBigNum(t2);

t2 += db;
printBigNum(t2);

etc.

Oh, well, I tried.

// BigNumber library
#include "BigNumber.h"

void setup() {   

	Serial.begin(115200);  

	BigNumber::begin();  // initialize library

	BigNumber result, ab, bb, cb, db, eb, to16;

	unsigned long a, b;
	unsigned int c, d;  // or unsigned long
	double e;

	to16 = "65536";

	// an example of typical values (vars, not constants):

	a = 23948398;
	b = 8380334;

	c = 135;
	d = 12032;

	e = 0.72348;

	ab = a;
	bb = b;
	cb = c;
	db = d;
	eb = e;

	// the actual formula:
        // result = (a * b) / (c * 65536 + d + e);
        // shall be result = 22653423.351809387532795061757447

        // casted to bignum
	// result = (ab * bb) / (cb * to16 + db + eb);

	// Serial.println(result);
	// printBigNum(result);

	BigNumber t1 = ab * bb;  //   ( a * b )
	printBigNum(t1);

	BigNumber t2 = cb * to16;  //   ( c * 65536 )
	printBigNum(t2);

	BigNumber t3 = t2 + db;  //   ( c * 65536  + d )
	printBigNum(t3);

	BigNumber t4 = t3 + eb;  //   ( c * 65536  +  d  +  e )
	printBigNum(t4);

	BigNumber t5 = t1 / t4;  //   ( a * b ) / ( c * 65536  +  d  +  e )
	printBigNum(t5);

}

void loop() {
};


//function to display a big number and free it afterwards
//modified println to print
void printBigNum (BigNumber n)
{
	char * s = n.toString ();
	Serial.println (s);
	free (s);
}  // end of printBignum
-229669692
8847360
8859392
8859392
-25

The negative value for the multiplication certainly looks wrong. I guess we will need to wait for Nick to join the discussion.

Compiled and run on 1284p so no issue with ram space..
Not sure the BigNumber lib can work with float/int/long/long_long variables as the input to the calculation. Would be great if it could..
:~

I've PMed to Nick so maybe he can help..
A possible workaround:

char buffer [40];
	//ab = a;
	ltoa(a, buffer, 10);
	ab = buffer;
        //bb = b;
	ltoa(b, buffer, 10);
	bb = buffer;

Gives a correct (a*b)..

This gives at least the integer calcs correctly, but still an issue with the float value e..

// BigNumber library
#include "BigNumber.h"

void setup() {   

	Serial.begin(115200);  

	BigNumber::begin(30);  // initialize library

	BigNumber result, ab, bb, cb, db, eb, to16;

	unsigned long a, b;
	unsigned int c, d;  // or unsigned long
	double e;

	to16 = "65536";

	// an example of typical values (vars, not constants):

	a = 23948398;
	b = 8380334;

	c = 135;
	d = 12032;

	e = 0.72348;

	//ab = a;
	//bb = b;
	//cb = c;
	//db = d;
	//eb = e;

	char buffer [40];
	ltoa(a, buffer, 10);
	ab = buffer;
	ltoa(b, buffer, 10);
	bb = buffer;
	ltoa(c, buffer, 10);
	cb = buffer;
	ltoa(d, buffer, 10);
	db = buffer;

	dtostrf(e, 8, 5, buffer);
	eb = buffer;

	// the actual formula:
	// result = (a * b) / (c * 65536 + d + e);
	// shall be result = 22653423.351809387532795061757447

	// casted to bignum
	// result = (ab * bb) / (cb * to16 + db + eb);

	// Serial.println(result);
	// printBigNum(result);

	BigNumber t1 = ab * bb;  //   ( a * b )
	Serial.println(t1);

	BigNumber t2 = cb * to16;  //   ( c * 65536 )
	Serial.println(t2);

	BigNumber t3 = t2 + db;  //   ( c * 65536  + d )
	Serial.println(t3);

	Serial.println(eb);    // print eb = 0.72348

	BigNumber t4 = t3 + eb;  //   ( c * 65536  +  d  +  e )
	Serial.println(t4);

	BigNumber t5 = t1 / t4;  //   ( a * b ) / ( c * 65536  +  d  +  e )
	Serial.println(t5);

}

void loop() {
};
200695574004932
8847360
8859392
0
8859392
22653425

The float to string conversion gives proper result, but still, assigning the string (with float) to a bignumber fails..

dtostrf(e, 8, 5, buffer);
Serial.print(buffer);
prints   0.72348

but

dtostrf(e, 8, 5, buffer);
eb = buffer;
Serial.print(eb);
prints  0

This gives the correct result with above sketch:

	dtostrf(e, 8, 5, buffer);
	eb = "0.72348";//buffer;
200695574004932
8847360
8859392.000000000000000000000000000000
0.72348
8859392.723480000000000000000000000000
22653423.351809387532795061757446641905

And this fails:

	dtostrf(e, 8, 5, buffer);
	eb = buffer;
200695574004932
8847360
8859392.000000000000000000000000000000
0
8859392.000000000000000000000000000000
22653425.201744318345999364290461467333

Any hint? :slight_smile:

It seems the library has got a problem with the reading the float string with a leading space.
Reading:

	dtostrf(e, 7, 5, buffer);
	eb = buffer;

works as the buffer = "0.72348"

This does not read into bignumber:

	dtostrf(e, 8, 5, buffer);
	eb = buffer;

as the buffer = "_0.72348"

:open_mouth:

It seems the library has got a problem with the reading the float string with a leading space.

Interesting. I'm sure that Nick will fix that, now that you've tracked down the source of the problem.