123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- {
- Copyright (c) 2007 by Daniel Mantione
- This unit implements a Tconstexprint type. This type simulates an integer
- type that can handle numbers from low(int64) to high(qword) calculations.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- 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. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit constexp;
- {$i fpcdefs.inc}
- {$modeswitch advancedrecords}
- interface
- {Avoid dependency on cpuinfo because the cpu directory isn't
- searched during utils building.}
- {$ifdef GENERIC_CPU}
- type bestreal=extended;
- {$else}
- {$ifdef x86}
- type bestreal=extended;
- {$else}
- type bestreal=double;
- {$endif}
- {$endif}
- type Tconstexprint=record
- function is_negative: boolean; inline;
- function extract_sign_abs(out abs: qword): boolean;
- procedure div_or_mod(const by: Tconstexprint; isdiv: boolean; out r: Tconstexprint);
- function tobestreal: bestreal;
- var
- overflow:boolean;
- case signed:boolean of
- false:
- (uvalue:qword);
- true:
- (svalue:int64);
- end;
- operator := (const u:qword):Tconstexprint;inline;
- operator := (const s:int64):Tconstexprint;inline;
- operator := (const c:Tconstexprint):qword;
- operator := (const c:Tconstexprint):int64;
- operator := (const c:Tconstexprint):bestreal;
- operator + (const a,b:Tconstexprint):Tconstexprint;
- operator - (const a,b:Tconstexprint):Tconstexprint;
- operator - (const a:Tconstexprint):Tconstexprint;
- operator * (const a,b:Tconstexprint):Tconstexprint;
- operator div (const a,b:Tconstexprint):Tconstexprint; inline;
- operator mod (const a,b:Tconstexprint):Tconstexprint; inline;
- operator / (const a,b:Tconstexprint):bestreal;
- operator = (const a,b:Tconstexprint):boolean;
- operator > (const a,b:Tconstexprint):boolean; inline; { Are reformulated using <. }
- operator >= (const a,b:Tconstexprint):boolean; inline;
- operator < (const a,b:Tconstexprint):boolean;
- operator <= (const a,b:Tconstexprint):boolean; inline;
- operator and (const a,b:Tconstexprint):Tconstexprint;
- operator or (const a,b:Tconstexprint):Tconstexprint;
- operator xor (const a,b:Tconstexprint):Tconstexprint;
- operator shl (const a,b:Tconstexprint):Tconstexprint;
- operator shr (const a,b:Tconstexprint):Tconstexprint;
- function tostr(const i:Tconstexprint):shortstring;overload;
- {****************************************************************************}
- implementation
- {****************************************************************************}
- uses
- cutils;
- function Tconstexprint.is_negative: boolean;
- begin
- result:=signed and (svalue<0);
- end;
- {$push} {$q-,r-}
- function Tconstexprint.extract_sign_abs(out abs: qword): boolean;
- begin
- result:=is_negative;
- if result then
- abs:=qword(-svalue)
- else
- abs:=uvalue;
- end;
- procedure Tconstexprint.div_or_mod(const by: Tconstexprint; isdiv: boolean; out r: Tconstexprint);
- var
- aa, bb: qword;
- negres: boolean;
- begin
- if by.uvalue=0 then
- begin
- r:=qword(-int64(isdiv)); { Something. All ones if div, all zeros if mod. }
- r.overflow:=true;
- exit;
- end;
- { the sign of a modulo operation only depends on the sign of the
- dividend }
- negres:=self.extract_sign_abs(aa) xor by.extract_sign_abs(bb) and isdiv;
- r.overflow:=self.overflow or by.overflow;
- if isdiv then
- r.uvalue:=aa div bb
- else
- r.uvalue:=aa mod bb;
- r.signed:=negres or (r.svalue>=0);
- if negres then
- begin
- r.svalue:=-r.svalue;
- r.overflow:=r.overflow or (r.svalue>0); { Strictly > 0! }
- end;
- end;
- {$pop}
- function Tconstexprint.tobestreal: bestreal;
- begin
- if overflow then
- internalerrorproc(200706095);
- if signed then
- result:=svalue
- else
- result:=uvalue;
- end;
- operator := (const u:qword):Tconstexprint;
- begin
- result.overflow:=false;
- result.signed:=false;
- result.uvalue:=u;
- end;
- operator := (const s:int64):Tconstexprint;
- begin
- result.overflow:=false;
- result.signed:=true;
- result.svalue:=s;
- end;
- operator := (const c:Tconstexprint):qword;
- begin
- if c.overflow then
- internalerrorproc(200706091);
- if c.is_negative then
- internalerrorproc(200706092);
- result:=c.uvalue;
- end;
- operator := (const c:Tconstexprint):int64;
- begin
- if c.overflow then
- internalerrorproc(200706093);
- if not c.signed and (c.svalue<0) then
- internalerrorproc(200706094);
- result:=c.svalue;
- end;
- operator := (const c:Tconstexprint):bestreal;
- begin
- if c.overflow then
- internalerrorproc(200706095);
- if c.signed then
- result:=c.svalue
- else
- result:=c.uvalue;
- end;
- {$push} {$q-,r-}
- operator + (const a,b:Tconstexprint):Tconstexprint;
- var aneg:boolean;
- begin
- result.overflow:=a.overflow or b.overflow;
- result.uvalue:=a.uvalue+b.uvalue;
- aneg:=a.is_negative;
- if aneg<>b.is_negative then
- { Negative + positive: cannot overflow, signed if fits (here and below: “fits” means “positive value that fits into svalue”) or if positive operand did fit. }
- result.signed:=(result.svalue>=0) or (a.svalue xor b.svalue<0)
- else if aneg then
- begin
- { Negative + negative: overflow if positive, always signed. }
- result.overflow:=result.overflow or (result.svalue>=0);
- result.signed:=true;
- end
- else
- begin
- { Positive + positive: overflow if became less, signed if fits. }
- result.overflow:=result.overflow or (result.uvalue<a.uvalue);
- result.signed:=result.svalue>=0;
- end;
- end;
- operator - (const a,b:Tconstexprint):Tconstexprint;
- var bneg:boolean;
- begin
- result.overflow:=a.overflow or b.overflow;
- result.uvalue:=a.uvalue-b.uvalue;
- bneg:=b.is_negative;
- if a.is_negative then
- begin
- { Negative − negative: cannot overflow, always signed.
- Negative - positive: overflow if positive or b did not fit, always signed. }
- result.signed:=true;
- if not bneg then
- result.overflow:=result.overflow or (b.svalue<0) or (result.svalue>=0);
- end
- else if bneg then
- begin
- { Positive - negative: overflow if became less, signed if fits. }
- result.overflow:=result.overflow or (result.uvalue<a.uvalue);
- result.signed:=result.svalue>=0;
- end
- else
- begin
- { Positive − positive: overflow if a < b but result is positive, signed if a < b or fits. }
- result.overflow:=result.overflow or (a.uvalue<b.uvalue) and (result.svalue>=0);
- result.signed:=(a.uvalue<b.uvalue) or (result.svalue>=0);
- end;
- end;
- operator - (const a:Tconstexprint):Tconstexprint;
- var aneg:boolean;
- begin
- aneg:=a.is_negative;
- result.svalue:=-a.svalue;
- result.overflow:=a.overflow or not aneg and (result.svalue>0); { Will trigger on > -Low(int64). }
- result.signed:=not (aneg and (a.svalue=Low(a.svalue))); { Unsigned only if negating Low(int64). }
- end;
- operator * (const a,b:Tconstexprint):Tconstexprint;
- var aa,bb:qword;
- negres:boolean;
- begin
- negres:=a.extract_sign_abs(aa) xor b.extract_sign_abs(bb);
- result.uvalue:=aa*bb;
- result.overflow:=a.overflow or b.overflow or
- (Hi(aa) or Hi(bb)<>0) and { Pretest to avoid division in small cases. Must be cheaper than two BsrQWords. }
- (bb<>0) and (high(qword) div bb<aa);
- result.signed:=negres or (result.svalue>=0);
- if negres then
- begin
- result.overflow:=result.overflow or (result.svalue<0);
- result.svalue:=-result.svalue;
- end;
- end;
- {$pop}
- operator div (const a,b:Tconstexprint):Tconstexprint;
- begin
- a.div_or_mod(b,true,result);
- end;
- operator mod (const a,b:Tconstexprint):Tconstexprint;
- begin
- a.div_or_mod(b,false,result);
- end;
- operator / (const a,b:Tconstexprint):bestreal;
- begin
- result:=a.tobestreal/b.tobestreal;
- end;
- operator = (const a,b:Tconstexprint):boolean;
- begin
- result:=(a.uvalue=b.uvalue) and (a.is_negative=b.is_negative);
- end;
- operator > (const a,b:Tconstexprint):boolean;
- begin
- result:=b<a;
- end;
- operator >= (const a,b:Tconstexprint):boolean;
- begin
- result:=not(a<b);
- end;
- operator < (const a,b:Tconstexprint):boolean;
- begin
- result:=a.is_negative;
- if result=b.is_negative then
- result:=a.uvalue<b.uvalue; { Works both with positive < positive and unsigned(negative) < unsigned(negative). }
- end;
- operator <= (const a,b:Tconstexprint):boolean;
- begin
- result:=not(b<a);
- end;
- operator and (const a,b:Tconstexprint):Tconstexprint;
- begin
- result.overflow:=false;
- result.signed:=a.signed or b.signed;
- result.uvalue:=a.uvalue and b.uvalue;
- end;
- operator or (const a,b:Tconstexprint):Tconstexprint;
- begin
- result.overflow:=false;
- result.signed:=a.signed or b.signed;
- result.uvalue:=a.uvalue or b.uvalue;
- end;
- operator xor (const a,b:Tconstexprint):Tconstexprint;
- begin
- result.overflow:=false;
- result.signed:=a.signed or b.signed;
- result.uvalue:=a.uvalue xor b.uvalue;
- end;
- operator shl (const a,b:Tconstexprint):Tconstexprint;
- begin
- if b.uvalue>=bitsizeof(a.uvalue) then
- exit(0);
- result.overflow:=false;
- result.signed:=a.signed; { signed(1) shl 63 does not fit into signed }
- result.uvalue:=a.uvalue shl b.uvalue;
- end;
- operator shr (const a,b:Tconstexprint):Tconstexprint;
- begin
- if b.uvalue>=bitsizeof(a.uvalue) then
- exit(0);
- result.overflow:=false;
- result.signed:=a.signed;
- result.uvalue:=a.uvalue shr b.uvalue;
- end;
- function tostr(const i:Tconstexprint):shortstring;overload;
- begin
- if i.signed then
- str(i.svalue,result)
- else
- str(i.uvalue,result);
- end;
- end.
|