Floating calculation gets wrong result

cancel
Showing results for 
Search instead for 
Did you mean: 

Floating calculation gets wrong result

581 Views
everkimage
Contributor IV

Hi,my mcu is MC9S12X,ide is CodeWarrior V5.1.

Codes like:

float gf_e_a, gf_e_b, gf_e_c;
void test(void)
{
  word va, vb, vc;
  
  va = 3000;
  vb = 89;
  vc = 2000;
  
  gf_e_a = 0;
  gf_e_b = 0;
  gf_e_c = 0;
  
  while(1)
  {
    gf_e_a = va;
    gf_e_b = vb;
    gf_e_c = vc;
        
    if(gf_e_c <= (gf_e_a * (1.0 - ((100 - gf_e_b)/20.0))))
    {
      gf_e_c = gf_e_c - 0.01;
    }
    else
    {
      gf_e_c = (gf_e_a * (1.0 - ((100 - gf_e_b)/20.0)));
    }
  }
}

I suppose it should goto 'else' and gf_e_c should be equal to (3000 * (1.0 - ((100 - 89)/20.0)) = 1350.

But the result is gf_e_c equal to 2006.

Then i check the assambly code:

330:  float gf_e_a, gf_e_b, gf_e_c;
  331:  void test(void)
  332:  {

  0000 1b98         [2]     LEAS  -8,SP
  333:    word va, vb, vc;
  334:    float res;
  335:    
  336:    va = 3000;
  0002 cc0bb8       [2]     LDD   #3000
  0005 6c86         [2]     STD   6,SP
  337:    vb = 89;
  0007 ce0059       [2]     LDX   #89
  000a 6e84         [2]     STX   4,SP
  338:    vc = 2000;
  000c cd07d0       [2]     LDY   #2000
  000f 6d82         [2]     STY   2,SP
  339:    
  340:    gf_e_a = 0;
  0011 c7           [1]     CLRB  
  0012 87           [1]     CLRA  
  0013 7c0000       [3]     STD   gf_e_a:2
  341:    gf_e_b = 0;
  0016 7c0000       [3]     STD   gf_e_b:2
  342:    gf_e_c = 0;
  0019 7c0000       [3]     STD   gf_e_c:2
  343:    
  344:    while(1)
  345:    {
  346:      gf_e_a = va;
  001c ec86         [3]     LDD   6,SP
  001e 1887         [2]     CLRX  
  0020 160000       [4]     JSR   _FUFLOAT
  0023 7c0000       [3]     STD   gf_e_a:2
  0026 7e0000       [3]     STX   gf_e_a
  347:      gf_e_b = vb;
  0029 ec84         [3]     LDD   4,SP
  002b b705         [1]     SEX   A,X
  002d 160000       [4]     JSR   _FUFLOAT
  0030 7c0000       [3]     STD   gf_e_b:2
  0033 7e0000       [3]     STX   gf_e_b
  348:      gf_e_c = vc;
  0036 ec82         [3]     LDD   2,SP
  0038 1887         [2]     CLRX  
  003a 160000       [4]     JSR   _FUFLOAT
  003d 7c0000       [3]     STD   gf_e_c:2
  0040 7e0000       [3]     STX   gf_e_c
  349:          
  350:      if(gf_e_c <= (gf_e_a * (1.0 - ((100 - gf_e_b)/20.0))))
  0043 fd0000       [3]     LDY   gf_e_b:2
  0046 35           [2]     PSHY  
  0047 fd0000       [3]     LDY   gf_e_b
  004a 35           [2]     PSHY  
  004b c7           [1]     CLRB  
  004c 87           [1]     CLRA  
  004d ce42c8       [2]     LDX   #17096
  0050 160000       [4]     JSR   _FSUB
  0053 18c7         [2]     CLRY  
  0055 6da1         [2]     STY   2,+SP
  0057 6c82         [2]     STD   2,SP
  0059 cc41a0       [2]     LDD   #16800
  005c 3b           [2]     PSHD  
  005d ec84         [3]     LDD   4,SP
  005f 160000       [4]     JSR   _FDIV
  0062 6ca1         [2]     STD   2,+SP
  0064 34           [2]     PSHX  
  0065 ce3f80       [2]     LDX   #16256
  0068 b764         [1]     TFR   Y,D
  006a 160000       [4]     JSR   _FSUB
  006d fd0000       [3]     LDY   gf_e_a:2
  0070 6da1         [2]     STY   2,+SP
  0072 fd0000       [3]     LDY   gf_e_a
  0075 35           [2]     PSHY  
  0076 160000       [4]     JSR   _FMUL
  0079 6ca1         [2]     STD   2,+SP
  007b 34           [2]     PSHX  
  007c b746         [1]     TFR   D,Y
  007e fc0000       [3]     LDD   gf_e_c:2
  0081 fe0000       [3]     LDX   gf_e_c
  0084 160000       [4]     JSR   _FCMP
  0087 1b84         [2]     LEAS  4,SP
  0089 2e16         [3/1]   BGT   *+24 ;abs = 00a1
  351:      {
  352:        gf_e_c = gf_e_c - 0.01;
  008b ccd70a       [2]     LDD   #55050
  008e 3b           [2]     PSHD  
  008f cebc23       [2]     LDX   #48163
  0092 34           [2]     PSHX  
  0093 fc0000       [3]     LDD   gf_e_c:2
  0096 fe0000       [3]     LDX   gf_e_c
  0099 160000       [4]     JSR   _FADD
  009c 1b84         [2]     LEAS  4,SP
  353:      }
  009e 060000       [3]     JMP   test:0x0019
  354:      else
  355:      {
  356:        gf_e_c = (gf_e_a * (1.0 - ((100 - gf_e_b)/20.0)));
  00a1 7d0000       [3]     STY   gf_e_c:2
  00a4 060000       [3]     JMP   test:0x001c
  357:      }
  358:    }
  359:    
  360:    while(1);
  361:  }

There is something wrong in 'else'!

If i use key word 'volatile' to define the gf_e_xxx,it works.

But i want to know how to solve it officially.

0 Kudos
6 Replies

566 Views
lama
NXP TechSupport
NXP TechSupport

Hi,

have you read my previous answer?

Is there still any issue with expected behavior or results based on code and optimization logic?

You are trying to fight against optimization process so it is necessary to safe all variables by modifiers static or volatile. If the optimizer sees that some process, variable,.... use useless to be processed then it is removed from process. Why to calculate or store anything what is not used anymore or does not influences next processes.
Best regards,

Ladislav

0 Kudos

572 Views
lama
NXP TechSupport
NXP TechSupport

Hi,

the "issue" is your understanding of an optimization process and its implementation. Explained in the item 2 bellow.

The variable gf_e_c is not necessary to be calculated because it is not used anymore in the next process. The value is absolutely random value.

How to solve it? Two solutions.

1) make the variable as a volatile
2)  move initialization of gf_e_c out of the while(1) cycle. If you use the initialization inside the cycle then the optimizer recognizes that the gf_e_c is not used in the loop as an input value for next cycle but it is initialized again (gf_e_c = vc;) so it is not necessary to be calculated and it is used somewhere else in some register or anywhere or nowhere.
Of course, there is one important question whether you want to use previous value gf_e_c in the loop for next comparison in the if(gf_e_c <= (... code line.

 

Your code

while(1)
{
gf_e_a = va;
gf_e_b = vb;
gf_e_c = vc;

if(gf_e_c <= (gf_e_c <= (gf_e_a * (1.0 - ((100 - gf_e_b)/20.0))))
...
...

 

Suggested change; gf_e_c is used as an input parameter for a next comparison and not initialized in the while(1) loop:

gf_e_a = va;
gf_e_b = vb;
gf_e_c = vc;

while(1)
{

if(gf_e_c <= (gf_e_c <= (gf_e_a * (1.0 - ((100 - gf_e_b)/20.0))))

...
...

Best regards,

Ladislav

 

 

533 Views
everkimage
Contributor IV

Thx very much for your help.

test() is an example to replay the issue.In my project code is:

 

if (Power.ReTime <= (((real32_T)Power.Cyc_timeN) * (1.0F - ((100.0F - ((real32_T)Power.group)) / 20.0F))))
{
  Power.ReTime = ((Power.ReTime) - 0.01);
}
else
{
  Power.ReTime = (((real32_T)Power.Cyc_timeN) * (1.0F - ((100.0F - ((real32_T)Power.group)) / 20.0F)));
}

 

The assembly code is:

 

221:      if (Power.ReTime <= (((real32_T)Power.Cyc_timeN) * (1.0F - ((100.0F - ((real32_T)Power.group)) / 20.0F))))
  0320 f60000       [3]     LDAB  Power:1324
  0323 87           [1]     CLRA  
  0324 b705         [1]     SEX   A,X
  0326 160000       [4]     JSR   _FUFLOAT
  0329 3b           [2]     PSHD  
  032a 34           [2]     PSHX  
  032b c7           [1]     CLRB  
  032c 87           [1]     CLRA  
  032d ce42c8       [2]     LDX   #17096
  0330 160000       [4]     JSR   _FSUB
  0333 18c7         [2]     CLRY  
  0335 6da1         [2]     STY   2,+SP
  0337 6c84         [2]     STD   4,SP
  0339 cc41a0       [2]     LDD   #16800
  033c 3b           [2]     PSHD  
  033d ec86         [3]     LDD   6,SP
  033f 160000       [4]     JSR   _FDIV
  0342 6ca1         [2]     STD   2,+SP
  0344 34           [2]     PSHX  
  0345 ce3f80       [2]     LDX   #16256
  0348 b764         [1]     TFR   Y,D
  034a 160000       [4]     JSR   _FSUB
  034d 1b84         [2]     LEAS  4,SP
  034f 6c82         [2]     STD   2,SP
  0351 fc0000       [3]     LDD   Power:408
  0354 6e80         [2]     STX   0,SP
  0356 b765         [1]     TFR   Y,X
  0358 b746         [1]     TFR   D,Y
  035a 160000       [4]     JSR   _FUFLOAT
  035d 3b           [2]     PSHD  
  035e 34           [2]     PSHX  
  035f ec86         [3]     LDD   6,SP
  0361 ee84         [3]     LDX   4,SP
  0363 160000       [4]     JSR   _FMUL
  0366 6ca1         [2]     STD   2,+SP
  0368 34           [2]     PSHX  
  0369 fc0000       [3]     LDD   Power:6
  036c fe0000       [3]     LDX   Power:4
  036f b746         [1]     TFR   D,Y
  0371 6e88         [2]     STX   8,SP
  0373 160000       [4]     JSR   _FCMP
  0376 1b84         [2]     LEAS  4,SP
  0378 2e11         [3/1]   BGT   *+19 ;abs = 038b
  222:      {
  223:        Power.ReTime = ((Power.ReTime) - 0.01);
  037a ccd70a       [2]     LDD   #55050
  037d 3b           [2]     PSHD  
  037e cebc23       [2]     LDX   #48163
  0381 34           [2]     PSHX  
  0382 b764         [1]     TFR   Y,D
  0384 ee88         [3]     LDX   8,SP
  0386 160000       [4]     JSR   _FADD
  224:      }
  0389 2010         [3]     BRA   *+18 ;abs = 039b
  225:      else
  226:      {
  227:        Power.ReTime = (((real32_T)Power.Cyc_timeN) * (1.0F - ((100.0F - ((real32_T)Power.group)) / 20.0F)));
  038b b764         [1]     TFR   Y,D
  038d 1887         [2]     CLRX  
  038f 160000       [4]     JSR   _FUFLOAT
  0392 3b           [2]     PSHD  
  0393 34           [2]     PSHX  
  0394 ec86         [3]     LDD   6,SP
  0396 ee84         [3]     LDX   4,SP
  0398 160000       [4]     JSR   _FMUL
  039b 1b84         [2]     LEAS  4,SP
  039d 7c0000       [3]     STD   Power:6
  03a0 7e0000       [3]     STX   Power:4
  228:      }

 

At 038b the first code of 'else'(TFR Y,D) wnna put Power.Cyc_timeN into D,It means Y equal to Power.Cyc_timeN in previous code.But Y is set to Power:6 at address 036f(TFR D,Y).

Structure 'Power' is used everywhere,should not be optimized.

0 Kudos

515 Views
lama
NXP TechSupport
NXP TechSupport

Hi,

Without getting entire project to see all dependencies it is not possible to say anything.

Or entire temporary (issue highlighting) project with comment at the line you see the issue.

Best regards,

Ladislav

 

0 Kudos

509 Views
everkimage
Contributor IV

I cann't provide the whole project for the sake of confidentiality.Please give me some advice based on these assembly codes.I make some comments:

221:      if (Power.ReTime <= (((real32_T)Power.Cyc_timeN) * (1.0F - ((100.0F - ((real32_T)Power.group)) / 20.0F))))
  0320 f60000       [3]     LDAB  Power:1324	//load Power.group into X:D
  0323 87           [1]     CLRA  
  0324 b705         [1]     SEX   A,X
  0326 160000       [4]     JSR   _FUFLOAT	//change it to float & push into stack
  0329 3b           [2]     PSHD  
  032a 34           [2]     PSHX  
  032b c7           [1]     CLRB  		//load 100.0f into X:D
  032c 87           [1]     CLRA  
  032d ce42c8       [2]     LDX   #17096
  0330 160000       [4]     JSR   _FSUB		//100.0f - (float)Power.group
  0333 18c7         [2]     CLRY  		//***Y==0
  0335 6da1         [2]     STY   2,+SP
  0337 6c84         [2]     STD   4,SP
  0339 cc41a0       [2]     LDD   #16800	//load 20.0f & push into stack
  033c 3b           [2]     PSHD  
  033d ec86         [3]     LDD   6,SP		
  033f 160000       [4]     JSR   _FDIV		//(100.0f-(float)Power.group)/20.0f
  0342 6ca1         [2]     STD   2,+SP
  0344 34           [2]     PSHX  
  0345 ce3f80       [2]     LDX   #16256	//load 1.0f
  0348 b764         [1]     TFR   Y,D
  034a 160000       [4]     JSR   _FSUB		//1.0f - (100.0f-(float)Power.group)/20.0f & save the result
  034d 1b84         [2]     LEAS  4,SP
  034f 6c82         [2]     STD   2,SP
  0351 fc0000       [3]     LDD   Power:408	//load (float)Power.Cyc_timeN
  0354 6e80         [2]     STX   0,SP
  0356 b765         [1]     TFR   Y,X
  0358 b746         [1]     TFR   D,Y		//***Y==Power.Cyc_timeN
  035a 160000       [4]     JSR   _FUFLOAT
  035d 3b           [2]     PSHD  
  035e 34           [2]     PSHX  
  035f ec86         [3]     LDD   6,SP
  0361 ee84         [3]     LDX   4,SP
  0363 160000       [4]     JSR   _FMUL		//Power.Cyc_timeN * (1.0f - (100.0f-(float)Power.group)/20.0f)
  0366 6ca1         [2]     STD   2,+SP		//save into stack
  0368 34           [2]     PSHX  
  0369 fc0000       [3]     LDD   Power:6	//load Power.ReTime,it's a float var
  036c fe0000       [3]     LDX   Power:4
  036f b746         [1]     TFR   D,Y		//***Y=low half of Power.ReTime
  0371 6e88         [2]     STX   8,SP		
  0373 160000       [4]     JSR   _FCMP		//CMP(Power.ReTime, Power.Cyc_timeN * (1.0f - (100.0f-(float)Power.group)/20.0f))
  0376 1b84         [2]     LEAS  4,SP
  0378 2e11         [3/1]   BGT   *+19 ;abs = 038b
  222:      {
  223:        Power.ReTime = ((Power.ReTime) - 0.01);
  037a ccd70a       [2]     LDD   #55050
  037d 3b           [2]     PSHD  
  037e cebc23       [2]     LDX   #48163
  0381 34           [2]     PSHX  
  0382 b764         [1]     TFR   Y,D
  0384 ee88         [3]     LDX   8,SP
  0386 160000       [4]     JSR   _FADD
  224:      }
  0389 2010         [3]     BRA   *+18 ;abs = 039b
  225:      else
  226:      {
  227:        Power.ReTime = (((real32_T)Power.Cyc_timeN) * (1.0F - ((100.0F - ((real32_T)Power.group)) / 20.0F)));
  038b b764         [1]     TFR   Y,D		//!!!!!!D should be Cyc_timeN,but at 036f,Y is set to low half of Power.ReTime
  038d 1887         [2]     CLRX  
  038f 160000       [4]     JSR   _FUFLOAT
  0392 3b           [2]     PSHD  
  0393 34           [2]     PSHX  
  0394 ec86         [3]     LDD   6,SP
  0396 ee84         [3]     LDX   4,SP
  0398 160000       [4]     JSR   _FMUL
  039b 1b84         [2]     LEAS  4,SP
  039d 7c0000       [3]     STD   Power:6
  03a0 7e0000       [3]     STX   Power:4
  228:      }
0 Kudos

576 Views
everkimage
Contributor IV

It's just like only store half of the result to gf_e_c.

Why?Compiler treat float as 4 bytes but 2 bytes at the end?

0 Kudos