• AVR Freaks

AnsweredHot!Pow() function not workig correctly

Author
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
2019/02/25 08:59:11 (permalink)
0

Pow() function not workig correctly

Target and IDE:
18F67K40 and IDEv4.10
 
Description:
I'm not getting the expected results for pow() math function.
I have included math.h and then used the simple function below to test it

#include "math.h"

double a = 0, x = 2, y = 8;
a = pow(x,y);

I get a=0, when I compile and run the code

Things I have tried so far,
1. I have used XC8(v2.05 and v1.45) , with same results.
2. I have used 24 bit and 32 bit for float, with same results.
3. I have tried typecasting around variables( a= (float)pow(float)x,(float)y)), with same results


For my application code, I need to convert 32bit int to float. See code below.
sign = (MT_int >> 31)?-1:1;
exp = MT_int & 0x7f800000;
exp >>= 23;
mant = MT_int & 0x007fffff;
temp_float2 = sign*(1 + mant)*pow(2,(exp - 127));

With mant=0 and exp=115, im expecting the result temp_float2=2.44E-4. However, I get temp_float2=3.4E38.

All other floating point calculations for my application code is working well.
Please suggest corrections.
#1
qhb
Superb Member
  • Total Posts : 9998
  • Reward points : 0
  • Joined: 2016/06/05 14:55:32
  • Location: One step ahead...
  • Status: offline
Re: Pow() function not workig correctly 2019/02/25 12:44:15 (permalink)
+2 (2)
This may be totally unrelated, but as you are using a K40 chip, are you enabling the NVMREG errata fix?
See: XC8 Table Array Workaround for PIC18FXXK40, Silicon Rev A3 (Array init failing)
 
 

Nearly there...
#2
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 08:19:00 (permalink)
0
Thanks for the post.
 
I did add +NVMREG under the Linker additional options after reading your post. That didn't make a difference to the pow() calculations in my original post.
 
Any other ideas?
#3
crosland
Super Member
  • Total Posts : 1603
  • Reward points : 0
  • Joined: 2005/05/10 10:55:05
  • Location: Bucks, UK
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 08:33:41 (permalink)
+2 (2)
kj6666
 
For my application code, I need to convert 32bit int to float. See code below.
sign = (MT_int >> 31)?-1:1;
exp = MT_int & 0x7f800000;
exp >>= 23;
mant = MT_int & 0x007fffff;
temp_float2 = sign*(1 + mant)*pow(2,(exp - 127));

WTF?
int i;
float f;
f = i;   // or f = i*1.0 or f = (float)i
#4
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 08:41:22 (permalink)
-1 (1)
Wish it was that easy.
 
The floating point number is stored as IEEE-754.
 
The value of a IEEE-754 number is computed as:
sign 2exponent mantissa
The sign is stored in bit 32. The exponent can be computed from bits 24-31 by subtracting 127. The mantissa (also known as significand or fraction) is stored in bits 1-23. An invisible leading bit (i.e. it is not actually stored) with value 1.0 is placed in front, then bit 23 has a value of 1/2, bit 22 has value 1/4 etc. As a result, the mantissa has a value between 1.0 and 2. If the exponent reaches -127 (binary 00000000), the leading 1 is no longer used to enable gradual underflow.
#5
rodims
Super Member
  • Total Posts : 1515
  • Reward points : 0
  • Joined: 2009/02/10 11:08:59
  • Location: 51.9627, 7.6262
  • Status: online
Re: Pow() function not workig correctly 2019/02/26 08:42:54 (permalink)
+1 (1)
Please do not place two completely different topics in one post.
You just add confusion for everyone.
 
As Crosland already "depicted": 
why do you even try to do the compilers work and twiddle with bits and bytes to convert from int to float ?
Event if it would calculate correctly, the efficiency likely is rather bad.
#6
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 08:49:55 (permalink)
-1 (1)
 
I tried doing it the simple way, as suggested by Crosland, and I get incorrect results. That is due to the fact that this is a 32 bit INT conversion to 32 bits float conversion. Hence I shared the post on IEEE-754 number.
 
One needs to do the following conversion to get the floating point number
 sign 2exponent mantissa
 
And therefore I need the pow() function to get the results. So please share information on how to get the correct results of pow() function.
 
Thanks for your replies
 
#7
rodims
Super Member
  • Total Posts : 1515
  • Reward points : 0
  • Joined: 2009/02/10 11:08:59
  • Location: 51.9627, 7.6262
  • Status: online
Re: Pow() function not workig correctly 2019/02/26 09:12:19 (permalink)
+1 (1)
I get a=0, when I compile and run the code

 

#include "math.h"

double a = 0, x = 2, y = 8;
a = pow(x,y);


 
I created a simple project for XC8 2.0 with Simulator (under MpLabX 5.15) with the New Project function for the PIC18F67K40. 

#include <xc.h>
#include "math.h"

void main(void) {
    double a = 0, x = 2, y = 8;
    a = pow(x,y);
    return;
}

 
Tracing in the simulator results in a equals 256.0.
I know that simulator and reality may differ, I cannot test with real hardware.
How do you check your results.
#8
rodims
Super Member
  • Total Posts : 1515
  • Reward points : 0
  • Joined: 2009/02/10 11:08:59
  • Location: 51.9627, 7.6262
  • Status: online
Re: Pow() function not workig correctly 2019/02/26 09:15:02 (permalink)
+1 (1)
Are you aware that the precision for int32 and a floating point with 24 or 32 bits are different ?
#9
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 09:24:36 (permalink)
0
I'm debugging it on the microcontroller. Please see the screenshot below that show a=0.0 for the pow function with x =2.0 and y=8.0.
Yes, I have tried bot 24 bit and 32 bit for floating point, with same results(I mentioned this in Original post)
 
 
#10
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 09:25:54 (permalink)
0
How do I attach an image to my post? It wont let me post with an image pated to this window
#11
rodims
Super Member
  • Total Posts : 1515
  • Reward points : 0
  • Joined: 2009/02/10 11:08:59
  • Location: 51.9627, 7.6262
  • Status: online
Re: Pow() function not workig correctly 2019/02/26 09:37:18 (permalink) ☼ Best Answerby kj6666 2019/02/27 10:07:51
+2 (2)
Yes, I have tried bot 24 bit and 32 bit for floating point, with same results(I mentioned this in Original post)

My question did not relate to your code, but that you might have wrong assumptions that you can simply convert ANY 32 bit integer to a float without loosing precision.
 
I did my test above with simulator again with XC 8 2.05.  May be not related but it cannot display the variable contents of variable a in the debugger, saying "out of scope" and value is 0.  So XC 8 2.00 behaves correctly in this test.
Please note that this observation may go into the wrong direction. I do not have much experience with XC8.
 
[edit: I repeated the test with a PIC16F18446 and XC 8 2.00 versa 2.05 -> same result as simulator]
 
If you have problems posting images, you can choose to upload it to e.g. https://imgur.com/upload
and refer either to the link here, or place as images with that URL here.
 
 
post edited by rodims - 2019/02/26 10:02:51
#12
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 10:21:37 (permalink)
0
That was it. I added the XC8 v2.0 and pow() function is working correctly now on the microcontroller.
Thanks!!
#13
crosland
Super Member
  • Total Posts : 1603
  • Reward points : 0
  • Joined: 2005/05/10 10:55:05
  • Location: Bucks, UK
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 10:30:24 (permalink)
+1 (1)
kj6666
Wish it was that easy.
 
The floating point number is stored as IEEE-754.
 
The value of a IEEE-754 number is computed as:
sign 2exponent mantissa
The sign is stored in bit 32. The exponent can be computed from bits 24-31 by subtracting 127. The mantissa (also known as significand or fraction) is stored in bits 1-23. An invisible leading bit (i.e. it is not actually stored) with value 1.0 is placed in front, then bit 23 has a value of 1/2, bit 22 has value 1/4 etc. As a result, the mantissa has a value between 1.0 and 2. If the exponent reaches -127 (binary 00000000), the leading 1 is no longer used to enable gradual underflow.


Having first written floating point math routines for a Z80 40 years ago I probably know more about it than you.
 
Just cast the int to a float.
 
If you are getting the wrong results then there is some other issue with your code.
 
#14
rodims
Super Member
  • Total Posts : 1515
  • Reward points : 0
  • Joined: 2009/02/10 11:08:59
  • Location: 51.9627, 7.6262
  • Status: online
Re: Pow() function not workig correctly 2019/02/26 10:40:55 (permalink)
+2 (2)
kj6666
That was it. I added the XC8 v2.0 and pow() function is working correctly now on the microcontroller.



Hm, that was a test, but it is not a solution.
You still would have to check whether the XC 8 2.05 debuger is cheating you/us.  pow might work perfectly ok, you would have to check without the debugger. If there is a real difference between the two compiler versions, I cannot track that.
 
And back to your real problem, which you did not really describe.
You might show an example code, simply casting int to float, where you think it does NOT give the expected results (which are ? ).
And which range of input values should it cover?
#15
davekw7x
Entropy++
  • Total Posts : 1811
  • Reward points : 0
  • Joined: 2012/01/16 12:01:07
  • Location: Second star on the right, straight on till morning
  • Status: offline
Re: Pow() function not workig correctly 2019/02/26 11:29:46 (permalink) ☄ Helpfulby kj6666 2019/02/27 10:08:01
+3 (3)
kj6666
...
For my application code, I need to convert 32bit int to float. See code below.

sign = (MT_int >> 31)?-1:1;
exp = MT_int & 0x7f800000;
exp >>= 23;
mant = MT_int & 0x007fffff;
temp_float2 = sign*(1 + mant)*pow(2,(exp - 127));

With mant=0 and exp=115, im expecting the result temp_float2=2.44E-4. However, I get temp_float2=3.4E38.

Here's what works for me.  (Note that the way you wrote it, the variable exp must be a 32 bit signed int; if it is an unsigned int, the second argument for pow() is a verrry large unsigned int, which can not be successfully promoted to a 32-bit float!  That's why it is important to show all of your code.)
#include <stdio.h>
#include <stdint.h>
#include <math.h>
    
// Put other include stuff and/or extern declarations here

void init_system(void);

void main(void)
{
    init_system(); // Initialize clock, timers, uart, etc...

    __delay_us(100); // Give things a little time to settle down.
    printf("\r\nCompiled on %s at %s by XC8 version %u\r\n",
            __DATE__, __TIME__, __XC8_VERSION);
    printf("sizeof(float) = %u, sizeof(double) = %u\r\n",
            sizeof(float), sizeof(double));

    double a = 0, x = 2, y = 8;
    a = pow(x, y);
    printf("x = %f, y = %f, a = %f\r\n", x, y, a);

    uint32_t MT_int = 0x39800000UL;
    int8_t  sign = (MT_int >> 31)?-1:1;
    uint32_t mant = MT_int & 0x007fffff;
    // This works, but I would probably call it iexp (or some such thing)
    // to keep from confusing with libm function exp()
    int32_t exp = MT_int & 0x7f800000;
    exp >>= 23;
    printf("sign = %d, exp = %lu, mant = %lu = 0x%08lX\r\n",
            sign, exp, mant, mant);
    float temp_float2 = sign*(1 + mant)*pow(2,(exp - 127));
    
    // For comparison: do it the easy way
    float *pfff = (float *)&MT_int;
    float fff = *pfff;
    printf("MT_int = %lu = 0x%08lX\r\n", MT_int, MT_int);
    printf("fff = %e = %f, temp_float = %e = %f\r\n",
            fff, fff, temp_float2, temp_float2);
    
    // To prove the point about exp:

    // The signed variable exp has a numerical value of  115
    double ipow = pow(2, exp-127); // I would probably use (2.0, iexp-127.0) here
    printf("ipow = %f\r\n", ipow);
    uint32_t uexp = MT_int & 0x7f800000;
    uexp >>= 23;
    // Note the problem here!
    double upow = pow(2, uexp-127);
    printf("upow = %f\r\n", upow);
    
    while (1) // Main loop
    {
        LED1_Toggle();
        __delay_ms(1000);
    } // End of main loop
} // End of main())


Output:


Compiled on Feb 26 2019 at 10:17:03 by XC8 version 2050
sizeof(float) = 4, sizeof(double) = 4
x = 2.000000, y = 8.000000, a = 256.000000
sign = 1, exp = 115, mant = 0 = 0x00000000
MT_int = 964689920 = 0x39800000
fff = 2.441406e-04 = 0.000244, temp_float = 2.441406e-04 = 0.000244
ipow = 0.000244
upow = inf

Tested on PIC18F27K40

MPLABX version 5.15, XC8 version 2.05, C99 mode---Free version at Optimization level 0 and level 2.


 
My test plan: The fact that printf works means there is no "issue" about the NVMREG errata.  Printf simply won't work if itthe erratum is needed but is not configured in the project.
Also, using the C99 mode assures me that it's using 32-bit floats, but I print out sizes just to make sure.
 
Note: I didn't bother testing with other compiler versions.  I did not use a debugger or simulator or anyotherdang thing.  Just real hardware running a production build at full speed. 
 
If this doesn't help, then how about packaging your entire project and posting the zip file?  Maybe someone can help you get to the bottom of things
 
Regards,

Dave
 
post edited by davekw7x - 2019/02/26 12:45:59

Sometimes I just can't help myself...
#16
kj6666
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2019/02/21 07:28:03
  • Location: 0
  • Status: offline
Re: Pow() function not workig correctly 2019/02/27 10:07:25 (permalink)
0
First of all, Thanks for all the inputs
 
I'm not exactly sure what fixed it. But here is the code with three implementations and the print output. One difference from my original post - I did typecast exp in my code.
 
1.MT_float=0.000244
2.MT_float=964689920.000000
3.MT_float=0.000244
 
 
void test_float()
{
unsigned long MT_int,MP_int;
double MT_float, MP_float;
signed long sign;
unsigned long exp;
unsigned int mant;

MT_int = 0x39800000;

 sign = (MT_int >> 31)?-1:1;
    exp = MT_int & 0x7f800000;
    exp >>= 23;
   mant = MT_int & 0x007fffff;
   MT_float = sign*(1 + mant)*pow(2,(float)exp - 127);
   printf("1.MT_float=%f\r\n",MT_float); 
  
 
   MT_float = (double)MT_int;
   printf("2.MT_float=%f\r\n",MT_float); 
   
  
   double *pfff = (double *)&MT_int;
   MT_float = *pfff;
   
   printf("3.MT_float=%f\r\n",MT_float);
}

#17
1and0
Access is Denied
  • Total Posts : 9611
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Pow() function not workig correctly 2019/02/27 22:15:25 (permalink)
+1 (1)
davekw7x

    float temp_float2 = sign*(1 + mant)*pow(2,(exp - 127));


kj6666

   MT_float = sign*(1 + mant)*pow(2,(float)exp - 127);


That should be
foo_float = sign*(1 + mant/(float)0x800000)*pow(2,exp - 127);

#18
davekw7x
Entropy++
  • Total Posts : 1811
  • Reward points : 0
  • Joined: 2012/01/16 12:01:07
  • Location: Second star on the right, straight on till morning
  • Status: offline
Re: Pow() function not workig correctly 2019/02/28 00:31:13 (permalink)
+1 (1)
Your correction to handling the significand is valid: Floating point division by 2.0 to the power 23 can work.  This was not obvious in the OP's example, for which the significand was zero.  (See Footnote)


On the other hand, as I tried to illustrate in my post...
Since the OP still has exp defined as a 32-bit unsigned int, the second argument to pow() is obtained by "promoting" the unsigned 32-bit value corresponding to 115 - 127, to a floating point value.  This blows up.

Using a signed int for the exp variable works, but the OP's solution of converting exp to a floating point variable before doing the arithmetic also works.



        // Unsigned arithmetic doesn't work if the result is supposed to
        // have a negative value!
        uint32_t uexp = 115;
        double uarg2 = (double)(uexp-127);
        double ufloat = pow(2, uarg2);
        printf("Using unsigned 32-bit int for the exp:\r\n");
        printf("  uarg2 =  %e, ufloat = %e\r\n\r\n", uarg2, ufloat);
        
        // Working with signed arithmetic works just dandy
        int32_t iexp = 115;
        double iarg2 = (double)(iexp-127);
        double ifloat = pow(2, iarg2);
        printf("Using signed 32-bit int for the exp:\r\n");
        printf("  iarg2 = %e, ifloat = %e\r\n\r\n", iarg2, ifloat);
        
        // Converting either of the two terms to a floating point variable
        // results in floating point arithmetic, which also gives
        // the correct answer since the uexp value is quite small.
        double farg2 = (double)uexp - 127;
        double ffloat = pow(2, farg2);
        printf("Casting the unsigned int to float in the expression:\r\n");
        printf("  farg2 = %e, ffloat = %e\r\n\r\n", farg2, ffloat);

 
(Note that floats and doubles are both 32-bits for XC8 version 2.0x in C99 mode.  I use doubles as a matter of habit.)

Output:

Using unsigned 32-bit int for the exp:
  uarg2 =  4.294967e+09, ufloat = inf

Using signed 32-bit int for the exp:
  iarg2 = -1.200000e+01, ifloat = 2.441406e-04

Casting the unsigned int to float in the expression:
  farg2 = -1.200000e+01, ffloat = 2.441406e-04

Bottom line: The correct answer for the argument is -12.0 and the result from the pow() function is correct as shown in examples 2 and 3 but not for the first one.

Regards,

Dave

Footnote:
Using floating point arithmetic for the conversion (and using the floating point library function pow()) to actually do the conversion is kind of "cheating."

I mean, after all, I can't imagine that internal conversion by the compiler would use floating point arithmetic, but for purposes of illustration, done properly, it can verify that internal representation is consistent with the definitions of IEEE-754.
 
My "practice" code for this is quite different from that of the OP, but the point of my previous post was to show the error that results from using unsigned arithmetic in an expression for which a negative value is expected to be promoted to a floating point value.
 
I didn't actually look at the part that converts the significand to a decimal-fraction mantissa, and I appreciate your correction.



post edited by davekw7x - 2019/02/28 00:42:40

Sometimes I just can't help myself...
#19
Jump to:
© 2019 APG vNext Commercial Version 4.5