12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2006 by the Free Pascal development team.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$ifdef FPC_INCLUDE_SOFTWARE_LONGWORD_TO_DOUBLE}
- function fpc_longword_to_double(i: longword): double; compilerproc;
- begin
- qword(result):=(qword(1075) shl 52) + i;
- result:=result - (qword(1) shl 52);
- end;
- {$endif FPC_INCLUDE_SOFTWARE_LONGWORD_TO_DOUBLE}
- {$if defined(FPU68881) or defined(FPUCOLDFIRE)}
- {$ifndef FPC_SYSTEM_HAS_ROUND}
- {$define FPC_SYSTEM_HAS_ROUND}
- function fpc_round_real(d : ValReal) : int64;compilerproc;
- type
- float64 = record
- high,low: longint;
- end;
- var
- tmp: double;
- j0: longint;
- hx: longword;
- sx: longint;
- const
- H2_52: array[0..1] of double = (
- 4.50359962737049600000e+15,
- -4.50359962737049600000e+15
- );
- Begin
- { This basically calculates trunc((d+2**52)-2**52) }
- hx:=float64(d).high;
- j0:=((hx shr 20) and $7ff) - $3ff;
- sx:=hx shr 31;
- hx:=(hx and $fffff) or $100000;
- if j0>=52 then { No fraction bits, already integer }
- begin
- if j0>=63 then { Overflow, let trunc() raise an exception }
- exit(trunc(d)) { and/or return +/-MaxInt64 if it's masked }
- else
- result:=((int64(hx) shl 32) or float64(d).low) shl (j0-52);
- end
- else
- begin
- { Rounding happens here. It is important that the expression is not
- optimized by selecting a larger type to store 'tmp'. }
- { The double cast should enforce a memory store and reload, which is the
- fastest way on a 68881/2 to enforce the rounding to double precision.
- The internal operation of the '88x is always in extended. If the rounding
- of the FPU is set to a different precision in the FPCR, the result is a
- a large performance penalty, according to the 68881/68882 Users Manual
- Section 2.2.2. So we keep the FPU in extended, but this means the rounding
- to double trick might conflict with tmp being a regvar. (KB) }
- {$ifdef FPU68881}
- tmp:=double(float64(H2_52[sx]+d));
- {$else}
- { The above doesn't affect the CF FPU. Its maximum precision is double. }
- tmp:=H2_52[sx]+d;
- {$endif}
- d:=tmp-H2_52[sx];
- hx:=float64(d).high;
- j0:=((hx shr 20) and $7ff)-$3ff;
- hx:=(hx and $fffff) or $100000;
- if j0<=20 then
- begin
- if j0<0 then
- exit(0)
- else { more than 32 fraction bits, low dword discarded }
- result:=hx shr (20-j0);
- end
- else
- result:=(int64(hx) shl (j0-20)) or (float64(d).low shr (52-j0));
- end;
- if sx<>0 then
- result:=-result;
- end;
- {$endif FPC_SYSTEM_HAS_ROUND}
- {$endif defined(FPU68881) or defined(FPUCOLDFIRE)}
|