problems calculation large doubles in MSP430

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
hi all!

I'm working on a program written on ANSI C for an emmbedded system.... to be
precise I am working on an MSP430 with a small webserver that will receive
some data into it's RAM through an external hardware and some interruptions.
What

I have to do is to get this data, do some calculations and display it
through the web server. My problem is, MSP430 compilator (I use IAR
emmbedded workbench) limits long doubles to 4 bytes, so I see myself with
problems when doing calculations under C with very large numbers. Do you
know a way arround it like a library to extend double size or a way to make
the compiler meet the standards ANSI C has for doubles? or maybe I have to
do math calculation to split the numbers and then rejoin them?

Cheers...



Re: problems calculation large doubles in MSP430

Quoted text here. Click to load it

You're expecting slightly more from ANSI standard C than you should.
While 4 bytes isn't quite enough for ANSI C compliant long double
(because of the requirement LDBL_DIG >= 10 and LDBL_EPSILON <= 1e-9),
it's still close enough that it's not a major violation of the
standard, and particularly not for a small-ish micro like the MSP430.
You ought to consider yourself lucky you have any FP support at all.

OTOH, are you really sure you *need* numbers larger than 1e37 in your
calculations and still have to do them inside your micro web-server?
Even the United States' national budget expressed in the smallest
currency unit used anywhere in the world and the resulting number
squared wouldn't yield numbers that large!  For real-world
measurements, choosing an appropriate unit and pre-cleaning your
formulae a bit should let you avoid this mess entirely.

No detection device in the world has a dynamic range of 1e37 ---
heck, hardly any *theory* ranges that far!

--
Hans-Bernhard Broeker ( snipped-for-privacy@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Re: problems calculation large doubles in MSP430
Quoted text here. Click to load it

There is no such thing as a "minor" violation of a standard. You
conform, or don't.

pete
--
snipped-for-privacy@fenelon.com "there's no room for enigmas in built-up areas."

Re: problems calculation large doubles in MSP430

Quoted text here. Click to load it
with
make

Humm...... ok... I give you a sample....

I get a variable that consists of this number :

0x00201582

, but I get it in two "chunks". The reason is not
important but, just so you know, I have to make a "volatile int" to a
pointer that can only be 2 bytes (compiler limitation) So what I do, I get
first 2 bytes the the other 2 as:

varHI = 0x0020
varLO = 0x1582

and I have to put them toguether to
multiply them by 'factor' (which value is 0x174b)

factor = 0x174b

If you get a good hexacalculator (windows calc does not do the job since it
doesn't accept 40 bit
values) the final result of this calculation is

result = 2EB54FB16

which I have to translate to a decimal result as 1253.8.....

let's see a clean sample of how i'd write it:


double Myfunction(void)
{
  volatile int varLO = *external16bitinfoLO ;
  volatile int varHI = *external16bitinfoHI;
  volatile int factor = *FACTOR ;
  double finalresult;  //remember, it's 4 byte double

  finalresult = (((varHI*0x10000)+varLO)*(factor)/1000000.0f);

  return(finalresult);

}


When I start calculating and I multiply the values, the container for this
operation is too small (a double that can only get 32bits, long double is
not accepted by my compiler), thus not finishing the calculation and
forgeting one of the digits of the final result, the 1st one or the last one
(meaning 2EB54FB1 without the last 6 or the oposite EB54FB16 without the
first 2). That is EXACTLY where my problem is rooted. I need a way to carry
on this simple calculations so that I can use the 4.5 bytes of the result
for my conversion to decimal (which after deleting all non necessary numbers
at the mantissa will be less than 32 bits)

So I see that, since my decimal result is shorter later on, there should be
some way to reduce the hexadecimal values, but how?

Thank's for your help, as you can see I am a bit new at this....

Yodai




Re: problems calculation large doubles in MSP430

[... Big Numbers ...]]
Quoted text here. Click to load it

OK so far.

Quoted text here. Click to load it

I presume that's by simple division by 1e7, so the final result is
1253.8149654.  The question becomes, "How many places beyond the
decimal do you really need?"  Consider the following simple-minded use
of a 4-byte float in gcc:

--- begin included file ---

C:\Dave>type float.c
#include <stdio.h>

int main(void)
{
   unsigned short var_hi = 0x20;
   unsigned short var_lo = 0x1582;
   unsigned int factor = 0x174b;
   float f = (float)var_hi;

   f *= 0x10000;
   f += var_lo;
   f *= factor;
   f /= 1e7f;

   printf("The result is %15.8f\n",f);
   return 0;
}

C:\Dave>gcc -ansi -pedantic -Wall float.c

C:\Dave>a
The result is   1253.81494141

C:\Dave>

--- end included file ---

That's good to 4 decimal places without trying.  If you need all
seven, it's going to be trickier.

HTH,
   -=Dave
                               -=Dave
--
Change is inevitable, progress is not.

Re: problems calculation large doubles in MSP430
[snip]
Quoted text here. Click to load it
get
it


I think I didn't express myself properly... it's not exactly as you say.....
the decimal representation of  2EB54FB16 is 12538149654 wich I afterwards
divide by 10000000 (decimal) and avoid all decimal positions except the
first, since I only need 1253.8

[snip again ]

so... what do you think? any idea?


Cheers...


Yodai





Re: problems calculation large doubles in MSP430

Quoted text here. Click to load it
since
say.....

If you need fixed-point calculations, prepare your factors so that the
divisor will be a power of 2 instead of a power of 10 (10^7 here). You can
then calculate the number in pieces (several longs) and combine after
round-off. The conversion to decimal can be performed last.

If you insist in calculating in decimal, do it from the start: store your
numbers in digit arrays and use the school longhand arithmetic on them
(slower than the pure binary arithmetic).

HTH

Tauno Voipio
tauno voipio @ iki fi




Re: problems calculation large doubles in MSP430
Quoted text here. Click to load it

Simply change the 15.8 in Dave's printf format to 15.1.  I think
you need to do some reading up on printf format specifiers.

--
Chuck F ( snipped-for-privacy@yahoo.com) ( snipped-for-privacy@worldnet.att.net)
   Available for consulting/temporary embedded and systems.
We've slightly trimmed the long signature. Click to see the full one.
Re: problems calculation large doubles in MSP430

Quoted text here. Click to load it
it
one
carry
numbers
be

Yes, it is clear that you're a bit new at this.  You have done two things
wrong here - first, you are not converting your integers to double in the
right places, and secondly you are not thinking about the problem like an
embedded programmer.

The key line is:
    finalresult = (((varHI*0x10000)+varLO)*(factor)/1000000.0f);

What this tells the C compiler is to take the 16-bit int "varHi" and
multiply it by the long int constant "0x10000".  This will automatically
protomote "varHi" to a 32-bit long.  Then it multiplies by the 16-bit int
"factor" - again, this will be automatically promoted to 32-bit long to
match the other side of the "*" operator.  The resulting numerator is still
a 32-bit long.  This is then to be divided by a float, so it must first be
promoted to a float, and the division is then carried out.  In other words,
the key part of your calculation, the one that overflows, is done in 32-bit
integer arithmetic.

If you simply change all your variables to doubles, you'd have no problems:
    double varHI = *(volatile int*) external16bitinfoHI;

A 32-bit double is perfectly capable of dealing with these numbers - it will
lose a few bits off the end, but these would be chopped in the rounding
anyway, and you only have about 24 bits of precision comming in in the first
place.

Of course, that's a totally daft way to deal with your calculation.  Think
about it again - you have a 32-bit value comming in, you need to multiply it
by a 16-bit value, then divide by 1 000 000.  The result is an integer,
scaled by 10.  There is no need for floating point anywhere - on a small
microcontroller, you should strive to avoid floating point and use integer
arithmetic where possible.  The answer is to split the 1000000 into bits,
and divide in such a way as to avoid overflow while keeping as much
precision as possible.  Depending on the possible ranges of the data, you
may need a 32-bit long for the result rather than a 16-bit int.

int MyFunction(void)
{
    int varHi = *(volatile int*) external16bitinfoHI;
    unsigned int varLo = *(volatile unsigned int*) external16bitinfoLo;
                                       // Must be unsigned !!
    long int var = ((long) varHi << 16) | varLo;
    int factor = *(volatile int*) FACTOR;
    int finalResult;

    // We want finalResult = (var * factor) / 1000000;
    finalResult = ((var / 64) * factor) / 15625;
    return finalResult;
}

An alternative, of course, would be to switch to msp-gcc, which has support
for 64-bit long longs (although it is still more efficient to stick to
16-bit and 32-bit data).

As a side note, 1.0 is a "double" constant, 1.0f is a single-precision float
constant.





Re: problems calculation large doubles in MSP430

Quoted text here. Click to load it

How large is "very large?"

Quoted text here. Click to load it

A bignum library like GNU MP might solve your problem, if it's not too
heavyweight and the licensing fits.  You'd probably have to pare any
such library down in any case.

Otherwise, without knowing more about your application, I guess you'll
just have to be careful.  Especially with addition and subtraction.

Regards,

                               -=Dave
--
Change is inevitable, progress is not.

Site Timeline