math.inc 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 by the Free Pascal development team.
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$ifdef FPC_INCLUDE_SOFTWARE_LONGWORD_TO_DOUBLE}
  11. function fpc_longword_to_double(i: longword): double; compilerproc;
  12. begin
  13. qword(result):=(qword(1075) shl 52) + i;
  14. result:=result - (qword(1) shl 52);
  15. end;
  16. {$endif FPC_INCLUDE_SOFTWARE_LONGWORD_TO_DOUBLE}
  17. {$if defined(FPU68881) or defined(FPUCOLDFIRE)}
  18. {$ifndef FPC_SYSTEM_HAS_ROUND}
  19. {$define FPC_SYSTEM_HAS_ROUND}
  20. function fpc_round_real(d : ValReal) : int64;compilerproc;
  21. type
  22. float64 = record
  23. high,low: longint;
  24. end;
  25. var
  26. tmp: double;
  27. j0: longint;
  28. hx: longword;
  29. sx: longint;
  30. const
  31. H2_52: array[0..1] of double = (
  32. 4.50359962737049600000e+15,
  33. -4.50359962737049600000e+15
  34. );
  35. Begin
  36. { This basically calculates trunc((d+2**52)-2**52) }
  37. hx:=float64(d).high;
  38. j0:=((hx shr 20) and $7ff) - $3ff;
  39. sx:=hx shr 31;
  40. hx:=(hx and $fffff) or $100000;
  41. if j0>=52 then { No fraction bits, already integer }
  42. begin
  43. if j0>=63 then { Overflow, let trunc() raise an exception }
  44. exit(trunc(d)) { and/or return +/-MaxInt64 if it's masked }
  45. else
  46. result:=((int64(hx) shl 32) or float64(d).low) shl (j0-52);
  47. end
  48. else
  49. begin
  50. { Rounding happens here. It is important that the expression is not
  51. optimized by selecting a larger type to store 'tmp'. }
  52. { The double cast should enforce a memory store and reload, which is the
  53. fastest way on a 68881/2 to enforce the rounding to double precision.
  54. The internal operation of the '88x is always in extended. If the rounding
  55. of the FPU is set to a different precision in the FPCR, the result is a
  56. a large performance penalty, according to the 68881/68882 Users Manual
  57. Section 2.2.2. So we keep the FPU in extended, but this means the rounding
  58. to double trick might conflict with tmp being a regvar. (KB) }
  59. {$ifdef FPU68881}
  60. tmp:=double(float64(H2_52[sx]+d));
  61. {$else}
  62. { The above doesn't affect the CF FPU. Its maximum precision is double. }
  63. tmp:=H2_52[sx]+d;
  64. {$endif}
  65. d:=tmp-H2_52[sx];
  66. hx:=float64(d).high;
  67. j0:=((hx shr 20) and $7ff)-$3ff;
  68. hx:=(hx and $fffff) or $100000;
  69. if j0<=20 then
  70. begin
  71. if j0<0 then
  72. exit(0)
  73. else { more than 32 fraction bits, low dword discarded }
  74. result:=hx shr (20-j0);
  75. end
  76. else
  77. result:=(int64(hx) shl (j0-20)) or (float64(d).low shr (52-j0));
  78. end;
  79. if sx<>0 then
  80. result:=-result;
  81. end;
  82. {$endif FPC_SYSTEM_HAS_ROUND}
  83. {$endif defined(FPU68881) or defined(FPUCOLDFIRE)}