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

**posted on**

December 9, 2003, 6:50 pm

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...

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

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.

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

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 ...]]

OK so far.

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.

Change is inevitable, progress is not.

Re: problems calculation large doubles in MSP430

[snip]

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

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

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

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.

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

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

How large is "very large?"

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.

Change is inevitable, progress is not.

#### Site Timeline

- » Powering a LPC2114 ARM7
- — Next thread in » Embedded Programming

- » Mocana SSH/SSL
- — Previous thread in » Embedded Programming

- » [AVR] What assembler to use?
- — Newest thread in » Embedded Programming

- » Serial EEPROM or Serial Flash?
- — Last Updated thread in » Embedded Programming

- » Monitoring internal voltages
- — The site's Newest Thread. Posted in » Raspberry Pi Group