strange result on floating point calculation


Hello,
I'm currently experiencing a problem with Keil ARM compiler on a STM32 target with hw FP unit. I can not explain the reason for this and I am looking forward to any explanation and possibility to avoid if possible.
Please find below a code snippet which shows the problem.

The first calculation gives a slightly different result to the two other ones. Although all values involved as well as the result should be lossless representable as a float number, result1 is slightly inprecise.


volatile u32   million = 1000000;

volatile float thousand = 1000.0f;

volatile float result1, result2, result3;

 

result1 = (float)million / 1000.0f;        // -> 1000.00006

result2 = (float)1000000 / 1000.0f;        // -> 1000

result3 = (float)million / thousand;       // -> 1000

Parents
  • Hello Thomas,

    Though I don't have hardware to test on, I did a quick test using the supplied FVPs, and can replicate your results (using Arm Compiler for Embedded 6.22).

    #include <stdio.h>
    
    void float_test(void){
    
    	volatile unsigned int	million = 1000000;
    	volatile float thousand = 1000.0f;
    	volatile float result1, result2, result3;
    
    
    	result1 = (float)million / 1000.0f;        // -> 1000.00006
    	result2 = (float)1000000 / 1000.0f;        // -> 1000
    	result3 = (float)million / thousand;       // -> 1000
    
    	printf("Million / 1000.0 = %f\n", result1);
    	printf("1000000 / 1000.0 = %f\n", result2);
    	printf("Million / Thousand = %f\n", result3);
    
    	return;
    }
    


    Million / 1000.0 = 1000.000061
    1000000 / 1000.0 = 1000.000000
    Million / Thousand = 1000.000000

    Looking at the low level code, I see a difference... for the first calculation (that resulting in slightly inaccurate result), the compiler used VMUL.F32 instruction to multiply 10^6 by 10^-3, whereas when thousand was used as a variable, the VDIV.F32 divide instruction was used.

    That is likely the cause of the lack of precision.

Reply
  • Hello Thomas,

    Though I don't have hardware to test on, I did a quick test using the supplied FVPs, and can replicate your results (using Arm Compiler for Embedded 6.22).

    #include <stdio.h>
    
    void float_test(void){
    
    	volatile unsigned int	million = 1000000;
    	volatile float thousand = 1000.0f;
    	volatile float result1, result2, result3;
    
    
    	result1 = (float)million / 1000.0f;        // -> 1000.00006
    	result2 = (float)1000000 / 1000.0f;        // -> 1000
    	result3 = (float)million / thousand;       // -> 1000
    
    	printf("Million / 1000.0 = %f\n", result1);
    	printf("1000000 / 1000.0 = %f\n", result2);
    	printf("Million / Thousand = %f\n", result3);
    
    	return;
    }
    


    Million / 1000.0 = 1000.000061
    1000000 / 1000.0 = 1000.000000
    Million / Thousand = 1000.000000

    Looking at the low level code, I see a difference... for the first calculation (that resulting in slightly inaccurate result), the compiler used VMUL.F32 instruction to multiply 10^6 by 10^-3, whereas when thousand was used as a variable, the VDIV.F32 divide instruction was used.

    That is likely the cause of the lack of precision.

Children