123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- {
- $Id$
- This file is part of the Free Pascal run time library.
- Copyright (c) 2000 by Jonas Maebe and other members of the
- Free Pascal development team
- Implementation of mathamatical Routines (only for real)
- 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.
- **********************************************************************}
- {****************************************************************************
- EXTENDED data type routines
- ****************************************************************************}
- {$define FPC_SYSTEM_HAS_PI}
- function pi : double;[internconst:in_pi];
- begin
- pi := 3.14159265358979320;
- end;
- {$define FPC_SYSTEM_HAS_ABS}
- function abs(d : extended) : extended;[internproc:in_abs_extended];
- {$define FPC_SYSTEM_HAS_SQR}
- function sqr(d : extended) : extended;[internproc:in_sqr_extended];
- {$define FPC_SYSTEM_HAS_SQRT}
- function sqrt(d : extended) : extended;[internproc:in_sqrt_extended];
- {
- function arctan(d : extended) : extended;[internconst:in_arctan_extended];
- begin
- runerror(207);
- end;
- function ln(d : extended) : extended;[internconst:in_ln_extended];
- begin
- runerror(207);
- end;
- function sin(d : extended) : extended;[internconst: in_sin_extended];
- begin
- runerror(207);
- end;
- function cos(d : extended) : extended;[internconst:in_cos_extended];
- begin
- runerror(207);
- end;
- function exp(d : extended) : extended;[internconst:in_const_exp];
- begin
- runerror(207);
- end;
- function frac(d : extended) : extended;[internconst:in_const_frac];
- begin
- runerror(207);
- end;
- }
- {$define FPC_SYSTEM_HAS_INT}
- {$warning FIX ME}
- function int(d : extended) : extended;[internconst:in_const_int];
- begin
- runerror(207);
- end;
- {$define FPC_SYSTEM_HAS_TRUNC}
- {$warning FIX ME}
- function trunc(d : extended) : int64;assembler;[internconst:in_const_trunc];
- { input: d in fr1 }
- { output: result in r3 }
- assembler;
- var
- temp:
- record
- case byte of
- 0: (l1,l2: longint);
- 1: (d: double);
- end;
- asm
- fctiwz fr1,fr1
- stfd fr1,temp.d
- lwz r3,temp.l1
- lwz r4,temp.l2
- end ['R3','F1'];
- {$define FPC_SYSTEM_HAS_ROUND}
- function round(d : extended) : longint;assembler;[internconst:in_const_round];
- { input: d in fr1 }
- { output: result in r3 }
- assembler;
- var
- temp:
- record
- case byte of
- 0: (l1,l2: longint);
- 1: (d: double);
- end;
- asm
- fctiw fr1,fr1
- stfd fr1,temp.d
- lwz r3,temp.l1
- lwz r4,temp.l2
- end ['R3','F1'];
- {$define FPC_SYSTEM_HAS_POWER}
- function power(bas,expo : extended) : extended;
- begin
- if bas=0 then
- begin
- if expo<>0 then
- power:=0.0
- else
- HandleError(207);
- end
- else if expo=0 then
- power:=1
- else
- { bas < 0 is not allowed }
- if bas<0 then
- handleerror(207)
- else
- power:=exp(ln(bas)*expo);
- end;
- {****************************************************************************
- Longint data type routines
- ****************************************************************************}
- function power(bas,expo : longint) : longint;
- begin
- if bas=0 then
- begin
- if expo<>0 then
- power:=0
- else
- HandleError(207);
- end
- else if expo=0 then
- power:=1
- else
- begin
- if bas<0 then
- begin
- if odd(expo) then
- power:=-round(exp(ln(-bas)*expo))
- else
- power:=round(exp(ln(-bas)*expo));
- end
- else
- power:=round(exp(ln(bas)*expo));
- end;
- end;
- {****************************************************************************
- Helper routines to support old TP styled reals
- ****************************************************************************}
- { warning: the following converts a little-endian TP-style real }
- { to a big-endian double. So don't byte-swap the TP real! }
- {$define FPC_SYSTEM_HAS_REAL2DOUBLE}
- function real2double(r : real48) : double;
- var
- res : array[0..7] of byte;
- exponent : word;
- begin
- { copy mantissa }
- res[6]:=0;
- res[5]:=r[1] shl 5;
- res[4]:=(r[1] shr 3) or (r[2] shl 5);
- res[3]:=(r[2] shr 3) or (r[3] shl 5);
- res[2]:=(r[3] shr 3) or (r[4] shl 5);
- res[1]:=(r[4] shr 3) or (r[5] and $7f) shl 5;
- res[0]:=(r[5] and $7f) shr 3;
- { copy exponent }
- { correct exponent: }
- exponent:=(word(r[0])+(1023-129));
- res[1]:=res[1] or ((exponent and $f) shl 4);
- res[0]:=exponent shr 4;
- { set sign }
- res[0]:=res[0] or (r[5] and $80);
- real2double:=double(res);
- end;
- {****************************************************************************
- Int to real helpers
- ****************************************************************************}
- const
- longint_to_real_helper: int64 = $4330000080000000;
- cardinal_to_real_helper: int64 = $430000000000000;
- int_to_real_factor: double = double(high(cardinal))+1.0;
- function fpc_int64_to_double(i: int64): double; compilerproc;
- assembler;
- { input: high(i) in r3, low(i) in r4 }
- { output: double(i) in f0 }
- var
- temp:
- record
- case byte of
- 0: (l1,l2: cardinal);
- 1: (d: double);
- end;
- asm
- lis r0,$4330
- stw r0,temp.l1
- xoris r3,r3,$8000
- stw r3,temp.l2
- lis r3,longint_to_real_helper@ha
- lfd fr1,longint_to_real_helper@l(r3)
- lfd fr0,temp.d
- stw r4,temp.l2
- fsub fr0,fr0,fr1
- lis r4,cardinal_to_real_helper@ha
- lfd fr1,cardinal_to_real_helper@l(r4)
- lis r3,int_to_real_factor@ha
- lfd fr3,temp
- lfd fr2,int_to_real_factor@l(r3)
- fsub fr3,fr3,fr1
- fmadd fr1,fr0,fr2,fr3
- end ['R0','R3','R4','F0','F1','F2','F3'];
- function fpc_qword_to_double(q: qword): double; compilerproc;
- assembler;
- { input: high(q) in r3, low(q) in r4 }
- { output: double(q) in f0 }
- var
- temp:
- record
- case byte of
- 0: (l1,l2: cardinal);
- 1: (d: double);
- end;
- asm
- lis r0,$4330
- stw r0,temp.l1
- stw r3,temp.l2
- lfd fr0,temp.d
- lis r3,cardinal_to_real_helper@ha
- lfd fr1,cardinal_to_real_helper@l(r3)
- stw r4,temp.l2
- fsub fr0,fr0,fr1
- lfd fr3,temp
- lis r3,int_to_real_factor@ha
- lfd fr2,int_to_real_factor@l(r3)
- fsub fr3,fr3,fr1
- fmadd fr1,fr0,fr2,fr3
- end ['R0','R3','F0','F1','F2','F3'];
- {
- $Log$
- Revision 1.8 2002-08-10 17:14:36 jonas
- * various fixes, mostly changing the names of the modifies registers to
- upper case since that seems to be required by the compiler
- Revision 1.7 2002/07/31 16:58:12 jonas
- * fixed conversion from int64/qword to double errors
- Revision 1.6 2002/07/29 21:28:17 florian
- * several fixes to get further with linux/ppc system unit compilation
- Revision 1.5 2002/07/28 21:39:29 florian
- * made abs a compiler proc if it is generic
- Revision 1.4 2002/07/28 20:43:49 florian
- * several fixes for linux/powerpc
- * several fixes to MT
- Revision 1.3 2001/12/02 16:19:45 jonas
- * fpu results are returned in fr1, not fr0
- Revision 1.2 2001/10/30 17:18:14 jonas
- * fixed fpc_int64_to_double and fpc_int64_to_double (fpc_int64_to_double
- is now mostly tested and should work fine, fpc_qword_to_double should
- work too since it's almost the same)
- Revision 1.1 2001/10/28 14:09:13 jonas
- + initial implementation, lots of things still missing
- }
|