int64.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. This file contains some helper routines for int64 and qword
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$Q- no overflow checking }
  13. {$R- no range checking }
  14. type
  15. tqwordrec = packed record
  16. low : dword;
  17. high : dword;
  18. end;
  19. function count_leading_zeros(q : qword) : longint;
  20. var
  21. r,i : longint;
  22. begin
  23. r:=0;
  24. for i:=0 to 31 do
  25. begin
  26. if (tqwordrec(q).high and (longint($80000000) shr i))<>0 then
  27. begin
  28. count_leading_zeros:=r;
  29. exit;
  30. end;
  31. inc(r);
  32. end;
  33. for i:=0 to 31 do
  34. begin
  35. if (tqwordrec(q).low and (longint($80000000) shr i))<>0 then
  36. begin
  37. count_leading_zeros:=r;
  38. exit;
  39. end;
  40. inc(r);
  41. end;
  42. count_leading_zeros:=r;
  43. end;
  44. function divqword(n,z : qword) : qword;[public,alias: 'FPC_DIV_QWORD'];
  45. var
  46. shift,lzz,lzn : longint;
  47. { one : qword; }
  48. begin
  49. divqword:=0;
  50. if n=0 then
  51. HandleErrorFrame(200,get_frame);
  52. lzz:=count_leading_zeros(z);
  53. lzn:=count_leading_zeros(n);
  54. { if the denominator contains less zeros }
  55. { then the numerator }
  56. { the d is greater than the n }
  57. if lzn<lzz then
  58. exit;
  59. shift:=lzn-lzz;
  60. n:=n shl shift;
  61. repeat
  62. if z>=n then
  63. begin
  64. z:=z-n;
  65. divqword:=divqword+(qword(1) shl shift);
  66. end;
  67. dec(shift);
  68. n:=n shr 1;
  69. until shift<0;
  70. end;
  71. function modqword(n,z : qword) : qword;[public,alias: 'FPC_MOD_QWORD'];
  72. var
  73. shift,lzz,lzn : longint;
  74. begin
  75. modqword:=0;
  76. if n=0 then
  77. HandleErrorFrame(200,get_frame);
  78. lzz:=count_leading_zeros(z);
  79. lzn:=count_leading_zeros(n);
  80. { if the denominator contains less zeros }
  81. { then the numerator }
  82. { the d is greater than the n }
  83. if lzn<lzz then
  84. begin
  85. modqword:=z;
  86. exit;
  87. end;
  88. shift:=lzn-lzz;
  89. n:=n shl shift;
  90. repeat
  91. if z>=n then
  92. z:=z-n;
  93. dec(shift);
  94. n:=n shr 1;
  95. until shift<0;
  96. modqword:=z;
  97. end;
  98. function divint64(n,z : int64) : int64;[public,alias: 'FPC_DIV_INT64'];
  99. var
  100. sign : boolean;
  101. q1,q2 : qword;
  102. c : comp;
  103. begin
  104. if n=0 then
  105. HandleErrorFrame(200,get_frame);
  106. { can the fpu do the work? }
  107. if fpuint64 then
  108. begin
  109. // the c:=comp(...) is necessary to shut up the compiler
  110. c:=comp(comp(z)/comp(n));
  111. divint64:=qword(c);
  112. end
  113. else
  114. begin
  115. sign:=false;
  116. if z<0 then
  117. begin
  118. sign:=not(sign);
  119. q1:=qword(-z);
  120. end
  121. else
  122. q1:=z;
  123. if n<0 then
  124. begin
  125. sign:=not(sign);
  126. q2:=qword(-n);
  127. end
  128. else
  129. q2:=n;
  130. { the div is coded by the compiler as call to divqword }
  131. if sign then
  132. divint64:=-(q1 div q2)
  133. else
  134. divint64:=q1 div q2;
  135. end;
  136. end;
  137. function modint64(n,z : int64) : int64;[public,alias: 'FPC_MOD_INT64'];
  138. var
  139. signed : boolean;
  140. r,nq,zq : qword;
  141. begin
  142. if n=0 then
  143. HandleErrorFrame(200,get_frame);
  144. if n<0 then
  145. begin
  146. nq:=-n;
  147. signed:=true;
  148. end
  149. else
  150. begin
  151. signed:=false;
  152. nq:=n;
  153. end;
  154. if z<0 then
  155. begin
  156. zq:=qword(-z);
  157. signed:=not(signed);
  158. end
  159. else
  160. zq:=z;
  161. r:=zq mod nq;
  162. if signed then
  163. modint64:=-int64(r)
  164. else
  165. modint64:=r;
  166. end;
  167. { multiplies two qwords
  168. the longbool for checkoverflow avoids a misaligned stack
  169. }
  170. function mulqword(f1,f2 : qword;checkoverflow : longbool) : qword;[public,alias: 'FPC_MUL_QWORD'];
  171. var
  172. _f1,bitpos : qword;
  173. l : longint;
  174. {$ifdef i386}
  175. r : qword;
  176. {$endif i386}
  177. begin
  178. {$ifdef i386}
  179. if not(checkoverflow) then
  180. begin
  181. asm
  182. movl f1+4,%edx
  183. movl f2+4,%ecx
  184. orl %ecx,%edx
  185. movl f2,%edx
  186. movl f1,%eax
  187. jnz .Lqwordmultwomul
  188. mull %edx
  189. jmp .Lqwordmulready
  190. .Lqwordmultwomul:
  191. imul f1+4,%edx
  192. imul %eax,%ecx
  193. addl %edx,%ecx
  194. mull f2
  195. add %ecx,%edx
  196. .Lqwordmulready:
  197. movl %eax,r
  198. movl %edx,r+4
  199. end;
  200. mulqword:=r;
  201. end
  202. else
  203. {$endif i386}
  204. begin
  205. mulqword:=0;
  206. bitpos:=1;
  207. // store f1 for overflow checking
  208. _f1:=f1;
  209. for l:=0 to 63 do
  210. begin
  211. if (f2 and bitpos)<>0 then
  212. mulqword:=mulqword+f1;
  213. f1:=f1 shl 1;
  214. bitpos:=bitpos shl 1;
  215. end;
  216. { if one of the operands is greater than the result an }
  217. { overflow occurs }
  218. if checkoverflow and (_f1 <> 0) and (f2 <>0) and
  219. ((_f1>mulqword) or (f2>mulqword)) then
  220. HandleErrorFrame(215,get_frame);
  221. end;
  222. end;
  223. { multiplies two int64 ....
  224. fpuint64 = false:
  225. ... using the the qword multiplication
  226. fpuint64 = true:
  227. ... using the comp multiplication
  228. the longbool for checkoverflow avoids a misaligned stack
  229. }
  230. function mulint64(f1,f2 : int64;checkoverflow : longbool) : int64;[public,alias: 'FPC_MUL_INT64'];
  231. var
  232. sign : boolean;
  233. q1,q2,q3 : qword;
  234. c : comp;
  235. begin
  236. { can the fpu do the work ? }
  237. if fpuint64 and not(checkoverflow) then
  238. begin
  239. // the c:=comp(...) is necessary to shut up the compiler
  240. c:=comp(comp(f1)*comp(f2));
  241. mulint64:=int64(c);
  242. end
  243. else
  244. begin
  245. sign:=false;
  246. if f1<0 then
  247. begin
  248. sign:=not(sign);
  249. q1:=qword(-f1);
  250. end
  251. else
  252. q1:=f1;
  253. if f2<0 then
  254. begin
  255. sign:=not(sign);
  256. q2:=qword(-f2);
  257. end
  258. else
  259. q2:=f2;
  260. { the q1*q2 is coded as call to mulqword }
  261. q3:=q1*q2;
  262. if checkoverflow and (q1 <> 0) and (q2 <>0) and
  263. ((q1>q3) or (q2>q3) or
  264. { the bit 63 can be only set if we have $80000000 00000000 }
  265. { and sign is true }
  266. ((tqwordrec(q3).high and longint($80000000))<>0) and
  267. ((q3<>(qword(1) shl 63)) or not(sign))
  268. ) then
  269. HandleErrorFrame(215,get_frame);
  270. if sign then
  271. mulint64:=-q3
  272. else
  273. mulint64:=q3;
  274. end;
  275. end;
  276. procedure qword_str(value : qword;var s : string);
  277. var
  278. hs : string;
  279. begin
  280. hs:='';
  281. repeat
  282. hs:=chr(longint(value mod 10)+48)+hs;
  283. value:=value div 10;
  284. until value=0;
  285. s:=hs;
  286. end;
  287. procedure int64_str(value : int64;var s : string);
  288. var
  289. hs : string;
  290. q : qword;
  291. begin
  292. if value<0 then
  293. begin
  294. q:=qword(-value);
  295. qword_str(q,hs);
  296. s:='-'+hs;
  297. end
  298. else
  299. qword_str(qword(value),s);
  300. end;
  301. procedure int_str_qword(v : qword;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD'];
  302. begin
  303. qword_str(v,s);
  304. if length(s)<len then
  305. s:=space(len-length(s))+s;
  306. end;
  307. procedure int_str_int64(v : int64;len : longint;var s : shortstring);[public,alias:'FPC_SHORTSTR_INT64'];
  308. begin
  309. int64_str(v,s);
  310. if length(s)<len then
  311. s:=space(len-length(s))+s;
  312. end;
  313. procedure int_str_qword(v : qword;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_QWORD'];
  314. var
  315. ss : shortstring;
  316. begin
  317. int_str_qword(v,len,ss);
  318. s:=ss;
  319. end;
  320. procedure int_str_int64(v : int64;len : longint;var s : ansistring);[public,alias:'FPC_ANSISTR_INT64'];
  321. var
  322. ss : shortstring;
  323. begin
  324. int_str_int64(v,len,ss);
  325. s:=ss;
  326. end;
  327. Function ValInt64(Const S: ShortString; var Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR'];
  328. type
  329. QWordRec = packed record
  330. l1,l2: longint;
  331. end;
  332. var
  333. u, temp, prev, maxint64, maxqword : qword;
  334. base : byte;
  335. negative : boolean;
  336. begin
  337. ValInt64 := 0;
  338. Temp:=0;
  339. Code:=InitVal(s,negative,base);
  340. if Code>length(s) then
  341. exit;
  342. { high(int64) produces 0 in version 1.0 (JM) }
  343. with qwordrec(maxint64) do
  344. begin
  345. l1 := longint($ffffffff);
  346. l2 := $7fffffff;
  347. end;
  348. with qwordrec(maxqword) do
  349. begin
  350. l1 := longint($ffffffff);
  351. l2 := longint($ffffffff);
  352. end;
  353. while Code<=Length(s) do
  354. begin
  355. case s[Code] of
  356. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  357. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  358. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  359. else
  360. u:=16;
  361. end;
  362. Prev:=Temp;
  363. Temp:=Temp*Int64(base);
  364. If (u >= base) or
  365. ((base = 10) and
  366. (maxint64-temp+ord(negative) < u)) or
  367. ((base <> 10) and
  368. (qword(maxqword-temp) < u)) or
  369. (prev > maxqword div qword(base)) Then
  370. Begin
  371. ValInt64 := 0;
  372. Exit
  373. End;
  374. Temp:=Temp+u;
  375. inc(code);
  376. end;
  377. code:=0;
  378. ValInt64:=int64(Temp);
  379. If Negative Then
  380. ValInt64:=-ValInt64;
  381. end;
  382. Function ValQWord(Const S: ShortString; var Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR'];
  383. type qwordrec = packed record
  384. l1,l2: longint;
  385. end;
  386. var
  387. u, prev, maxqword: QWord;
  388. base : byte;
  389. negative : boolean;
  390. begin
  391. ValQWord:=0;
  392. Code:=InitVal(s,negative,base);
  393. If Negative or (Code>length(s)) Then
  394. Exit;
  395. with qwordrec(maxqword) do
  396. begin
  397. l1 := $ffffffff;
  398. l2 := $ffffffff;
  399. end;
  400. while Code<=Length(s) do
  401. begin
  402. case s[Code] of
  403. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  404. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  405. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  406. else
  407. u:=16;
  408. end;
  409. prev := ValQWord;
  410. If (u>=base) or
  411. ((QWord(maxqword-u) div QWord(base))<prev) then
  412. Begin
  413. ValQWord := 0;
  414. Exit
  415. End;
  416. ValQWord:=ValQWord*QWord(base) + u;
  417. inc(code);
  418. end;
  419. code := 0;
  420. end;
  421. {
  422. $Log$
  423. Revision 1.7 2000-12-10 15:00:14 florian
  424. * val for int64 hopefully works now correct
  425. Revision 1.6 2000/12/09 20:52:40 florian
  426. * val for dword and qword didn't handle the max values
  427. correctly
  428. * val for qword works again
  429. + val with int64/qword and ansistring implemented
  430. Revision 1.5 2000/12/07 17:19:47 jonas
  431. * new constant handling: from now on, hex constants >$7fffffff are
  432. parsed as unsigned constants (otherwise, $80000000 got sign extended
  433. and became $ffffffff80000000), all constants in the longint range
  434. become longints, all constants >$7fffffff and <=cardinal($ffffffff)
  435. are cardinals and the rest are int64's.
  436. * added lots of longint typecast to prevent range check errors in the
  437. compiler and rtl
  438. * type casts of symbolic ordinal constants are now preserved
  439. * fixed bug where the original resulttype wasn't restored correctly
  440. after doing a 64bit rangecheck
  441. Revision 1.4 2000/11/17 17:01:23 jonas
  442. * fixed bug for val when processing -2147483648 and low(int64) (merged)
  443. Revision 1.3 2000/07/28 12:29:49 jonas
  444. * fixed web bug1069
  445. * fixed similar (and other) problems in val() for int64 and qword
  446. (both merged from fixes branch)
  447. Revision 1.2 2000/07/13 11:33:44 michael
  448. + removed logs
  449. }