constexp.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. {
  2. Copyright (c) 2007 by Daniel Mantione
  3. This unit implements a Tconstexprint type. This type simulates an integer
  4. type that can handle numbers from low(int64) to high(qword) calculations.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit constexp;
  19. {$i fpcdefs.inc}
  20. {$modeswitch advancedrecords}
  21. interface
  22. {Avoid dependency on cpuinfo because the cpu directory isn't
  23. searched during utils building.}
  24. {$ifdef GENERIC_CPU}
  25. type bestreal=extended;
  26. {$else}
  27. {$ifdef x86}
  28. type bestreal=extended;
  29. {$else}
  30. type bestreal=double;
  31. {$endif}
  32. {$endif}
  33. type Tconstexprint=record
  34. function is_negative: boolean; inline;
  35. function extract_sign_abs(out abs: qword): boolean;
  36. procedure div_or_mod(const by: Tconstexprint; isdiv: boolean; out r: Tconstexprint);
  37. function tobestreal: bestreal;
  38. var
  39. overflow:boolean;
  40. case signed:boolean of
  41. false:
  42. (uvalue:qword);
  43. true:
  44. (svalue:int64);
  45. end;
  46. operator := (const u:qword):Tconstexprint;inline;
  47. operator := (const s:int64):Tconstexprint;inline;
  48. operator := (const c:Tconstexprint):qword;
  49. operator := (const c:Tconstexprint):int64;
  50. operator := (const c:Tconstexprint):bestreal;
  51. operator + (const a,b:Tconstexprint):Tconstexprint;
  52. operator - (const a,b:Tconstexprint):Tconstexprint;
  53. operator - (const a:Tconstexprint):Tconstexprint;
  54. operator * (const a,b:Tconstexprint):Tconstexprint;
  55. operator div (const a,b:Tconstexprint):Tconstexprint; inline;
  56. operator mod (const a,b:Tconstexprint):Tconstexprint; inline;
  57. operator / (const a,b:Tconstexprint):bestreal;
  58. operator = (const a,b:Tconstexprint):boolean;
  59. operator > (const a,b:Tconstexprint):boolean; inline; { Are reformulated using <. }
  60. operator >= (const a,b:Tconstexprint):boolean; inline;
  61. operator < (const a,b:Tconstexprint):boolean;
  62. operator <= (const a,b:Tconstexprint):boolean; inline;
  63. operator and (const a,b:Tconstexprint):Tconstexprint;
  64. operator or (const a,b:Tconstexprint):Tconstexprint;
  65. operator xor (const a,b:Tconstexprint):Tconstexprint;
  66. operator shl (const a,b:Tconstexprint):Tconstexprint;
  67. operator shr (const a,b:Tconstexprint):Tconstexprint;
  68. function tostr(const i:Tconstexprint):shortstring;overload;
  69. {****************************************************************************}
  70. implementation
  71. {****************************************************************************}
  72. uses
  73. cutils;
  74. function Tconstexprint.is_negative: boolean;
  75. begin
  76. result:=signed and (svalue<0);
  77. end;
  78. {$push} {$q-,r-}
  79. function Tconstexprint.extract_sign_abs(out abs: qword): boolean;
  80. begin
  81. result:=is_negative;
  82. if result then
  83. abs:=qword(-svalue)
  84. else
  85. abs:=uvalue;
  86. end;
  87. procedure Tconstexprint.div_or_mod(const by: Tconstexprint; isdiv: boolean; out r: Tconstexprint);
  88. var
  89. aa, bb: qword;
  90. negres: boolean;
  91. begin
  92. if by.uvalue=0 then
  93. begin
  94. r:=qword(-int64(isdiv)); { Something. All ones if div, all zeros if mod. }
  95. r.overflow:=true;
  96. exit;
  97. end;
  98. { the sign of a modulo operation only depends on the sign of the
  99. dividend }
  100. negres:=self.extract_sign_abs(aa) xor by.extract_sign_abs(bb) and isdiv;
  101. r.overflow:=self.overflow or by.overflow;
  102. if isdiv then
  103. r.uvalue:=aa div bb
  104. else
  105. r.uvalue:=aa mod bb;
  106. r.signed:=negres or (r.svalue>=0);
  107. if negres then
  108. begin
  109. r.svalue:=-r.svalue;
  110. r.overflow:=r.overflow or (r.svalue>0); { Strictly > 0! }
  111. end;
  112. end;
  113. {$pop}
  114. function Tconstexprint.tobestreal: bestreal;
  115. begin
  116. if overflow then
  117. internalerrorproc(200706095);
  118. if signed then
  119. result:=svalue
  120. else
  121. result:=uvalue;
  122. end;
  123. operator := (const u:qword):Tconstexprint;
  124. begin
  125. result.overflow:=false;
  126. result.signed:=false;
  127. result.uvalue:=u;
  128. end;
  129. operator := (const s:int64):Tconstexprint;
  130. begin
  131. result.overflow:=false;
  132. result.signed:=true;
  133. result.svalue:=s;
  134. end;
  135. operator := (const c:Tconstexprint):qword;
  136. begin
  137. if c.overflow then
  138. internalerrorproc(200706091);
  139. if c.is_negative then
  140. internalerrorproc(200706092);
  141. result:=c.uvalue;
  142. end;
  143. operator := (const c:Tconstexprint):int64;
  144. begin
  145. if c.overflow then
  146. internalerrorproc(200706093);
  147. if not c.signed and (c.svalue<0) then
  148. internalerrorproc(200706094);
  149. result:=c.svalue;
  150. end;
  151. operator := (const c:Tconstexprint):bestreal;
  152. begin
  153. if c.overflow then
  154. internalerrorproc(200706095);
  155. if c.signed then
  156. result:=c.svalue
  157. else
  158. result:=c.uvalue;
  159. end;
  160. {$push} {$q-,r-}
  161. operator + (const a,b:Tconstexprint):Tconstexprint;
  162. var aneg:boolean;
  163. begin
  164. result.overflow:=a.overflow or b.overflow;
  165. result.uvalue:=a.uvalue+b.uvalue;
  166. aneg:=a.is_negative;
  167. if aneg<>b.is_negative then
  168. { Negative + positive: cannot overflow, signed if fits (here and below: “fits” means “positive value that fits into svalue”) or if positive operand did fit. }
  169. result.signed:=(result.svalue>=0) or (a.svalue xor b.svalue<0)
  170. else if aneg then
  171. begin
  172. { Negative + negative: overflow if positive, always signed. }
  173. result.overflow:=result.overflow or (result.svalue>=0);
  174. result.signed:=true;
  175. end
  176. else
  177. begin
  178. { Positive + positive: overflow if became less, signed if fits. }
  179. result.overflow:=result.overflow or (result.uvalue<a.uvalue);
  180. result.signed:=result.svalue>=0;
  181. end;
  182. end;
  183. operator - (const a,b:Tconstexprint):Tconstexprint;
  184. var bneg:boolean;
  185. begin
  186. result.overflow:=a.overflow or b.overflow;
  187. result.uvalue:=a.uvalue-b.uvalue;
  188. bneg:=b.is_negative;
  189. if a.is_negative then
  190. begin
  191. { Negative − negative: cannot overflow, always signed.
  192. Negative - positive: overflow if positive or b did not fit, always signed. }
  193. result.signed:=true;
  194. if not bneg then
  195. result.overflow:=result.overflow or (b.svalue<0) or (result.svalue>=0);
  196. end
  197. else if bneg then
  198. begin
  199. { Positive - negative: overflow if became less, signed if fits. }
  200. result.overflow:=result.overflow or (result.uvalue<a.uvalue);
  201. result.signed:=result.svalue>=0;
  202. end
  203. else
  204. begin
  205. { Positive − positive: overflow if a < b but result is positive, signed if a < b or fits. }
  206. result.overflow:=result.overflow or (a.uvalue<b.uvalue) and (result.svalue>=0);
  207. result.signed:=(a.uvalue<b.uvalue) or (result.svalue>=0);
  208. end;
  209. end;
  210. operator - (const a:Tconstexprint):Tconstexprint;
  211. var aneg:boolean;
  212. begin
  213. aneg:=a.is_negative;
  214. result.svalue:=-a.svalue;
  215. result.overflow:=a.overflow or not aneg and (result.svalue>0); { Will trigger on > -Low(int64). }
  216. result.signed:=not (aneg and (a.svalue=Low(a.svalue))); { Unsigned only if negating Low(int64). }
  217. end;
  218. operator * (const a,b:Tconstexprint):Tconstexprint;
  219. var aa,bb:qword;
  220. negres:boolean;
  221. begin
  222. negres:=a.extract_sign_abs(aa) xor b.extract_sign_abs(bb);
  223. result.uvalue:=aa*bb;
  224. result.overflow:=a.overflow or b.overflow or
  225. (Hi(aa) or Hi(bb)<>0) and { Pretest to avoid division in small cases. Must be cheaper than two BsrQWords. }
  226. (bb<>0) and (high(qword) div bb<aa);
  227. result.signed:=negres or (result.svalue>=0);
  228. if negres then
  229. begin
  230. result.overflow:=result.overflow or (result.svalue<0);
  231. result.svalue:=-result.svalue;
  232. end;
  233. end;
  234. {$pop}
  235. operator div (const a,b:Tconstexprint):Tconstexprint;
  236. begin
  237. a.div_or_mod(b,true,result);
  238. end;
  239. operator mod (const a,b:Tconstexprint):Tconstexprint;
  240. begin
  241. a.div_or_mod(b,false,result);
  242. end;
  243. operator / (const a,b:Tconstexprint):bestreal;
  244. begin
  245. result:=a.tobestreal/b.tobestreal;
  246. end;
  247. operator = (const a,b:Tconstexprint):boolean;
  248. begin
  249. result:=(a.uvalue=b.uvalue) and (a.is_negative=b.is_negative);
  250. end;
  251. operator > (const a,b:Tconstexprint):boolean;
  252. begin
  253. result:=b<a;
  254. end;
  255. operator >= (const a,b:Tconstexprint):boolean;
  256. begin
  257. result:=not(a<b);
  258. end;
  259. operator < (const a,b:Tconstexprint):boolean;
  260. begin
  261. result:=a.is_negative;
  262. if result=b.is_negative then
  263. result:=a.uvalue<b.uvalue; { Works both with positive < positive and unsigned(negative) < unsigned(negative). }
  264. end;
  265. operator <= (const a,b:Tconstexprint):boolean;
  266. begin
  267. result:=not(b<a);
  268. end;
  269. operator and (const a,b:Tconstexprint):Tconstexprint;
  270. begin
  271. result.overflow:=false;
  272. result.signed:=a.signed or b.signed;
  273. result.uvalue:=a.uvalue and b.uvalue;
  274. end;
  275. operator or (const a,b:Tconstexprint):Tconstexprint;
  276. begin
  277. result.overflow:=false;
  278. result.signed:=a.signed or b.signed;
  279. result.uvalue:=a.uvalue or b.uvalue;
  280. end;
  281. operator xor (const a,b:Tconstexprint):Tconstexprint;
  282. begin
  283. result.overflow:=false;
  284. result.signed:=a.signed or b.signed;
  285. result.uvalue:=a.uvalue xor b.uvalue;
  286. end;
  287. operator shl (const a,b:Tconstexprint):Tconstexprint;
  288. begin
  289. if b.uvalue>=bitsizeof(a.uvalue) then
  290. exit(0);
  291. result.overflow:=false;
  292. result.signed:=a.signed; { signed(1) shl 63 does not fit into signed }
  293. result.uvalue:=a.uvalue shl b.uvalue;
  294. end;
  295. operator shr (const a,b:Tconstexprint):Tconstexprint;
  296. begin
  297. if b.uvalue>=bitsizeof(a.uvalue) then
  298. exit(0);
  299. result.overflow:=false;
  300. result.signed:=a.signed;
  301. result.uvalue:=a.uvalue shr b.uvalue;
  302. end;
  303. function tostr(const i:Tconstexprint):shortstring;overload;
  304. begin
  305. if i.signed then
  306. str(i.svalue,result)
  307. else
  308. str(i.uvalue,result);
  309. end;
  310. end.