home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 14 Text / 14-Text.zip / C6_BUGS.ZIP / C6_20071.BUG < prev    next >
Text File  |  1990-09-11  |  5KB  |  138 lines

  1. Q63053 Operands Reversed in C 6.00 Divide Operation
  2. Microsoft C Compiler (C)
  3. 6.00   | 6.00
  4. MS-DOS | OS/2
  5.  
  6. Summary:
  7.  
  8. Under certain situations, the Microsoft C version 6.00 compiler can
  9. generate code that causes the denominator in a division operation to
  10. be divided by the numerator instead of the other way around.
  11.  
  12. The following code, compiled under default optimizations with
  13. Microsoft C version 6.00, demonstrates the problem and causes the
  14. following error:
  15.  
  16.    run-time error M6103: Math
  17.    - floating-point error: divide by 0
  18.  
  19. More Information:
  20.  
  21. The problem apparently occur only when the denominator contains both a
  22. double value and a function parameter, and the numerator is a global
  23. float. Also, the next statement apparently must contain an expression
  24. utilizing the result of the operation. This prerequisites to the
  25. problem seem to indicate that the problem is directly tied to
  26. optimizations removing common subexpressions.
  27.  
  28. In the example below, the denominator in the first assignment
  29. statement in set_adc() is divided by the numerator. Therefore, instead
  30. of receiving 26.0/2.56 cast to an int, i gets a value of 0, or
  31. 2.56/26.0 cast to an int.
  32.  
  33. The following are several possible workarounds to the problem:
  34.  
  35. 1. Disable optimizations.
  36.  
  37. 2. Declare the numerator locally or as a double instead of a float.
  38.  
  39. 3. Use a global float variable in the denominator instead of parameter.
  40.  
  41. 4. Don't use a double value in the denominator.
  42.  
  43. 5. Cast the denominator as a float before division.
  44.  
  45. 6. Break up assignment statements with a function call.
  46.  
  47. 7. Use the /qc compiler option.
  48.  
  49. Code Example
  50. ------------
  51.  
  52. float f1;
  53. float f2=26.0f;   // Works if f2 is declared locally or as double.
  54.  
  55. void set_adc(float width)
  56. {
  57. // Works if width declared as local variable instead of parameter.
  58.    int i;
  59.    i=(int)(f2/(2.56*width));
  60.       // Works if used with float constant 2.56f.
  61.       // Works if denominator cast as float.
  62.       // Works if broken up with function call
  63.       //      such as printf("hello");.
  64.    f1=f2/i;
  65. }
  66.  
  67. void main(void)
  68. {
  69.    set_adc(1.0f);
  70. }
  71.  
  72. The section of mixed source and assembly below shows the assembly
  73. instructions generated by default optimizations. The troublesome
  74. instruction [FDIVP  ST(1),ST] is at offset 0023.
  75.  
  76. Following the logic below, width is pushed onto the coprocessor
  77. stack, ST. Then it is multiplied by 2.56. Then _f2 is pushed onto the
  78. coprocessor stack, ST making the above result ST(1). Finally, the
  79. FDIVP instruction takes ST(1), the denominator, and divides it by ST,
  80. _f2 - the numerator.
  81.  
  82. The rest is to be expected, __ftol is called to convert the float to
  83. an integer. The result, 0, is moved from the AX register into the
  84. local variable i. Then i is pushed onto the coprocessor stack, ST,
  85. and then the FDIVR instruction divides _f2 by this value causing the
  86. divide by 0 error.
  87.  
  88. 8:          i=(int)(f2/(2.56*width));
  89. 9:          f1=f2/i;
  90. 0047:0014 9B             WAIT
  91. 0047:0015 D94604         FLD       DWord Ptr [width]
  92. 0047:0018 9B             WAIT
  93. 0047:0019 DC0EB802       FMUL      QWord Ptr [__fpinit+e (02B8)]
  94. 0047:001D 9B             WAIT
  95. 0047:001E D9064200       FLD       DWord Ptr [_f2 (0042)]
  96. 0047:0022 9B             WAIT
  97. 0047:0023 DEF9           FDIVP     ST(1),ST                  ; wrong
  98. 0047:0025 E8001B         CALL      __ftol (1B28)
  99. 0047:0028 8946FE         MOV       Word Ptr [i],AX
  100. 0047:002B 9B             WAIT
  101. 0047:002C DF46FE         FILD      Word Ptr [i]
  102. 0047:002F 9B             WAIT
  103. 0047:0030 D83E4200       FDIVR     DWord Ptr [_f2 (0042)]
  104. 0047:0034 9B             WAIT
  105. 0047:0035 D91ED004       FSTP      DWord Ptr [_f1 (04D0)]
  106. 0047:0039 90             NOP
  107. 0047:003A 9B             WAIT
  108.  
  109. The following code generated with disabled optimizations shows the
  110. correct method of doing this. Width is pushed onto the coprocessor
  111. stack, ST. Width is then multiplied by 2.56 with the result stored in
  112. ST. The FDIVR instruction then divides _f2 by the above value, and
  113. after conversion, i equals 10 as it is supposed to.
  114.  
  115. 8:          i=(int)(f2/(2.56*width));
  116. 0047:0016 9B             WAIT
  117. 0047:0017 D94604         FLD       DWord Ptr [width]
  118. 0047:001A 9B             WAIT
  119. 0047:001B DC0EB802       FMUL      QWord Ptr [__fpinit+e (02B8)]
  120. 0047:001F 9B             WAIT
  121. 0047:0020 D83E4200       FDIVR     DWord Ptr [_f2 (0042)]   ; right
  122. 0047:0024 E8091B         CALL      __ftol (1B30)
  123. 0047:0027 8946FE         MOV       Word Ptr [i],AX
  124. 9:          f1=f2/i;
  125. 0047:002A 9B             WAIT
  126. 0047:002B D9064200       FLD       DWord Ptr [_f2 (0042)]
  127. 0047:002F 9B             WAIT
  128. 0047:0030 DE76FE         FIDIV     Word Ptr [i]
  129. 0047:0033 9B             WAIT
  130. 0047:0034 D91ED004       FSTP      DWord Ptr [_f1 (04D0)]
  131. 0047:0038 90             NOP
  132. 0047:0039 9B             WAIT
  133.  
  134. Keywords:  buglist6.00
  135.  
  136. COPYRIGHT Microsoft Corporation, 1990.
  137. Updated  90/07/26 05:20
  138.