Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

calculation for float in pic18f2550 gives wrong answer

Status
Not open for further replies.

ep.hobbyiest

Full Member level 4
Joined
Jul 24, 2014
Messages
212
Helped
1
Reputation
2
Reaction score
1
Trophy points
18
Activity points
1,487
i am facing some problem while doing calculation of float. i need to use the float values in micr0 and in nano's that is 10^(-6) to 10^(-9).
and deviation is much larger.
so is their any algorithm which can do floating point calculation easily.
 

which compiler are you using? I think XC uses 24 bit float number by default, which should limit the amount of significative values... try changing it to 32 bits...
 

Can you scale the values and use fixed point operations?
If you know the domain and range of the problem, then (in my experience) you can generally avoid floating point.
Susan
 

@Kurenai_ryu yes i am using xc8 compiler. i don't know how to change it 24bit to 32 bit.

@Aussie Susan No. it is bit difficult to avoid floating point. in the calculation there are most of the real numbers rather than integer.
 

I guess I come from a period where there were no floating point processors and so any floating point work was done in software and was incredibly slow (especially on Z80 like systems with clock speeds of 1MHz).
Therefore, statements like "it is a bit difficult to avoid floating point" to me indicates that you have not really understood what the calculations are really doing and the actual difference between real and (scaled) integer representations of the same values.
If you like, you could show us the calculations you are wanting to perform and the input domain and I could show how to do this with scaled integers.
Susan
 

yes sir.
calculation i am doing include value of capacitor and inductor.
I want to find out the answer for
F=1/(2*pi*(C*L)^(1/2))
and
C = 82*10^(-6))
L = 0.001*10^(-9).
so which method can gives correct answer.
 

yes sir.
calculation i am doing include value of capacitor and inductor.
I want to find out the answer for
F=1/(2*pi*(C*L)^(1/2))
and
C = 82*10^(-6))
L = 0.001*10^(-9).
so which method can gives correct answer.

The calculation will occupy 17 or 18 decimal places, internally.

For this case, input the values as uF and uH. The answer will be MHz.
 

You are dealing with pico Henries????? Seriously!
Or have you mixed up the L and C values?
Anyway, the approach is still the same.
Following BradtheRad's comment, and going back to my original question asking for the domain of the values, you need to select a set of units that makes the values integers.
You also need to consider the range of the partial results and the word size of the values. I'm going to assume that you have 32-bit integers available, which means that we want to keep values less than +/- 2147483648.
The first operation will be the multiplication of the L and C and so you want to make sure that both numbers are in range from 1 to about 46000 (multiply 46000 by itself and it will still fit into a 32-bit signed value).
Therefore I would recommend that you keep the domains between 1 and 10000. When you consider practical L and C values, that means you should express C as nF (which means you can express 1nF up to 10uF - if this is an LC oscillator then that is reasonable; the alternative is 1pF to 10nF and simply adjust the final scaling value) and L in uH (i.e. 1uH to 10mH).
Looking ahead to the fact that we will have a square root operation, it might be better to select calculation scaling factors that add to an even number so that the square root will given an integral power of 10. For example, if we stay with the nF (10^-9) and uH (10^-6), when you multiply then, the scaling factor will be 10^-15 and the square root will require a scaling factor of 10^-7.5. Therefore you could multiply (say) the L value by 10 (i.e. its base scaling factor will be 10^-7).
Therefore the first part of your calculation might be to multiply these 2 integer values, remembering (but not including in the code) the scaling factors for now. Assuming your values are actually C=82nF and L=1uH, then the product would be "82 * 10 = 820" and there would be an implied scaling factor of 10^-16.
The square root part is also fairly easy: if you Google "integer square root c code" there are a number of code examples to chose from, many of which use 32-bit integers. The square root of the scaling factor is also easy - halve it.
Therefore the square root of the LC part will be 28 (the integer square root of 820) and the implied scaling factor will be 10^-8.
The constant pi (or even 2*pi) is also fairly straight forward if we multiply it by some suitable factor. We have assumed that we are dealing with 32-bit integers and so know that the square root function will have a range from 1 to about 46000, so we what to keep the scaled value of 2*pi to also be less than about 46000.
2*pi = 6.283185 so we can use a number like 6283 with an implied scaling factor or 10^-3.
Therefore the last multiplication in the denominator will be 28 * 6283 = 175924 and the implied scaling factor is 10^-11.
When it comes to the final step of the inverse function, you can now trivially convert the 175924 to floating point, invert it and then multiply by 10^11. A number like 175924 has an inverse of 5.6843*10^-6 so the final answer is 568.4KHz.
Now, according to my calculator and using the same starting numbers, the answer should be 555.8KHz which means that we have calculated a value that is within 2%. The vast majority of components (especially inductors and capacitors) will have values that vary more than that and so the calculations are reasonable.
As you can see, we have used floating point only for the final step (the numeric inversion). By knowing the domains better, you may be able to select more appropriate scaling factors that can reduce the errors even more, but the above is certainly acceptable for practical use.
Susan
 
thank you sir.
I try several ways like
ignoring decimal point and after placing point
reducing zero's from calculation means consider 10 instead of 1000.
but every time answer get changed.
 

It is easiest if you deal with even quantities of zeroes, when you move the decimal point.

Looking at Aussie Susan's post #8:

Looking ahead to the fact that we will have a square root operation, it might be better to select calculation scaling factors that add to an even number so that the square root will given an integral power of 10.
 

The basis for this is as follows:
sqrt(y*z) = sqrt(y) * sqrt(z)
i.e. the square root of a product is the product of the individual square roots.
Now if (say) z is an even power of 10, then the square root will also be some nice power of 10 [sqrt(10^4) = 10^2].
However if z is an odd multiple of 10 then there will be a factor of sqrt(10) = 3.1623... that needs to be considered. I'm guessing that this could be the source of your error.
Susan
 

so I dusted my pic18f26j50, and tested your values:

Code:
#include <math.h>

...

volatile float Cval=82e-6;
volatile float Lval=0.001e-9;
volatile float Freq;
//volatile so the compiler doesn't do it at host

...

//in main()

Freq=1/(2*M_PI*sqrt(Cval*Lval));

//now I show via a buffer I prepared...

memcpy(&ToSendDataBuffer[26], &Freq, 4);

//and just 'cos I don't like floats I sent the float as ascii too...
myftoa(Freq,&ToSendDataBuffer[34],0);

and the result it give is:

hex value (24 bits) 0x4B8618

ascii value: 17575936.0

that hex value correspond to 1.7575936E7

according my calculator your true answer to Freq should be 17575723.2 or 1.7575724e7 (0x4b861796 in 32 bits) so the error is about 0.001%

to me, a simple man, I should be happy with this results...

but if I change the compiler setting on XC8 to get a 32 bit float

the new Freq values I get are:

hex value: 0x4B861795 (could you compare with the real value? it has 1 bit of difference!!!)

ascii value: 17575721.6 (with one decimal)

that hex value correspond to 1.7575722E7

which still has a small difference 0.00001% with my calculator (64 bit yeah!)


so....

unless you are pestering about that 0.001% of difference (but you still can get it better by changing to 32 bits) I'm pretty sure your problem is in another part of your program.
 
This also comes back to the precision of the measurements and how many significant figures you use for the initial values. Inductors and capacitors typically are expressed to 2 and perhaps 3 significant figures and are made to anywhere between 1 and 20% accuracy (especially the capacitors).
In reality, trying to get better than about 1% is a waste of time and effort.
Susan
 

Thank you for your reply.
@Kurenai_ryu i tried it by your way. but answer is same. i have uploaded file .c file. i also have done changes from 24bit to 32bit float length.
 

Attachments

  • cal.txt
    5.2 KB · Views: 51

oh god!!!

WHAT IS THIS?????
Code:
DisplayNum(0x80,(unsigned int)ans);

mmm

it seems there is a prototype somewhere
Code:
void DisplayNum(unsigned char add,unsigned char num);

WTF!!!!

so...
you have a float (ans) which contains a big big number (around 17000000) then you cast it to int (via (unsigned int)ans) and fed it to an unknown function that has single bytes (char) as argument?????

first: You have to know that an (unsigned int) in this microcontroller have a value range from 0 to 65535... so of course casting (unsigned int)ans will fail completely (17000000>65535 so it will get lost somewhere)...

second: I dunno what kind of sorcery you expect from DisplayNum(), but I think it only displays a 8-bit number (hence the unsigned char argument), if you feed it a 16 bit number, it will "crop" the upper 8 bits and just show you whatever value it has in the lower bits...

you need a proper DisplayNumFloat or just a function to display a float number in your LCD...

I think it could work like this, but its better if you make your own implementation... (which could show the Freq in a human understandable value)

Code:
void DisplayNumFloat(unsigned char add,float num){ //display it in MHz
    unsigned char i;
    unsigned char mess[5];
    unsigned int Kh; //too cheap
    Kh=(unsigned int)(num/1e3);
    for(i=5;i>0;i--){
        mess[i-1]=(unsigned char)(Kh % 10)|0x30;
	Kh=Kh/10;
    }
    //actual
    DisplayNum(add++,mess[0]);
    DisplayNum(add++,mess[1]);
    DisplayChar(add++,'.'); //this one I'm expecting you to change
    DisplayNum(add++,mess[2]);
    DisplayNum(add++,mess[3]);
    DisplayNum(add++,mess[4]);
}


...

and in initialization()
DisplayNumFloat(0x80,ans);
 

I think a restricted programming license is the best solution. Restrict everyone to 1MHz Z80 for their first year, it really teaches you how to program efficiently! (worked for me but my only choice in those days was Z80, 8080 or CDP1802 :sad:)

Don't you agree Sir Susan. :-D

Brian.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top