bfloatfunc.pp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804
  1. program bfloatfunc;
  2. {$mode objfpc}{$H+}
  3. uses
  4. SysUtils, Math;
  5. { Utility functions }
  6. function GetRealTime(const st: TSystemTime): Real;
  7. begin
  8. Result := st.Hour*3600.0 + st.Minute*60.0 + st.Second + st.MilliSecond/1000.0;
  9. end;
  10. {$push}
  11. {$warn 5057 off}
  12. function GetRealTime : Real;
  13. var
  14. st:TSystemTime;
  15. begin
  16. GetLocalTime(st);
  17. result:=GetRealTime(st);
  18. end;
  19. {$pop}
  20. function IIf(Condition: Boolean; TrueRes, FalseRes: Integer): Integer; inline;
  21. begin
  22. if Condition then
  23. Result := TrueRes
  24. else
  25. Result := FalseRes;
  26. end;
  27. const
  28. {$ifdef IN_TESTS}
  29. ITERATIONS = $8;
  30. {$else}
  31. ITERATIONS = 33554432;
  32. {$endif}
  33. { TTestAncestor }
  34. type
  35. TTestAncestor = class
  36. private
  37. FStartTime: Real;
  38. FEndTime: Real;
  39. FAvgTime: Real;
  40. procedure SetStartTime;
  41. procedure SetEndTime;
  42. protected
  43. procedure DoTestIteration(Iteration: Integer); virtual; abstract;
  44. public
  45. constructor Create; virtual;
  46. destructor Destroy; override;
  47. procedure Run;
  48. function TestTitle: shortstring; virtual; abstract;
  49. function WriteResults: Boolean; virtual; abstract;
  50. property RunTime: Real read FAvgTime;
  51. end;
  52. TTestClass = class of TTestAncestor;
  53. TFloat32Test = class(TTestAncestor)
  54. protected
  55. FResultStorage: array[0..7] of Single;
  56. FExpected: array[0..7] of Single;
  57. class function IsEqual(Value, Reference: Single): Boolean; static;
  58. public
  59. function WriteResults: Boolean; override;
  60. end;
  61. TFloat32OneInputTest = class(TFloat32Test)
  62. protected
  63. FInputs: array[0..7] of Single;
  64. procedure DoTestIteration(Iteration: Integer); override;
  65. function DoFunc(Input: Single): Single; virtual; abstract;
  66. end;
  67. TFloat32TwoInputTest = class(TFloat32Test)
  68. protected
  69. FInputs: array[0..7] of array[0..1] of Single;
  70. procedure DoTestIteration(Iteration: Integer); override;
  71. function DoFunc(Input1, Input2: Single): Single; virtual; abstract;
  72. end;
  73. TSingleIntPair = record
  74. S: Single;
  75. N: Integer;
  76. end;
  77. TFloat32FloatIntTest = class(TFloat32Test)
  78. protected
  79. FInputs: array[0..7] of TSingleIntPair;
  80. procedure DoTestIteration(Iteration: Integer); override;
  81. function DoFunc(Float: Single; N: Integer): Single; virtual; abstract;
  82. end;
  83. TFloat64Test = class(TTestAncestor)
  84. protected
  85. FResultStorage: array[0..7] of Double;
  86. FExpected: array[0..7] of Double;
  87. class function IsEqual(Value, Reference: Double): Boolean; static;
  88. public
  89. function WriteResults: Boolean; override;
  90. end;
  91. TFloat64OneInputTest = class(TFloat64Test)
  92. protected
  93. FInputs: array[0..7] of Double;
  94. procedure DoTestIteration(Iteration: Integer); override;
  95. function DoFunc(Input: Double): Double; virtual; abstract;
  96. end;
  97. TFloat64TwoInputTest = class(TFloat64Test)
  98. protected
  99. FInputs: array[0..7] of array[0..1] of Double;
  100. procedure DoTestIteration(Iteration: Integer); override;
  101. function DoFunc(Input1, Input2: Double): Double; virtual; abstract;
  102. end;
  103. TDoubleIntPair = record
  104. D: Double;
  105. N: Integer;
  106. end;
  107. TFloat64FloatIntTest = class(TFloat64Test)
  108. protected
  109. FInputs: array[0..7] of TDoubleIntPair;
  110. procedure DoTestIteration(Iteration: Integer); override;
  111. function DoFunc(Float: Double; N: Integer): Double; virtual; abstract;
  112. end;
  113. { Test classes for actual tests }
  114. { 32-bit floating-point }
  115. TFloat32MinTest = class(TFloat32TwoInputTest)
  116. protected
  117. function DoFunc(Input1, Input2: Single): Single; override;
  118. public
  119. constructor Create; override;
  120. function TestTitle: shortstring; override;
  121. end;
  122. TFloat32ImplicitMinTest = class(TFloat32MinTest)
  123. protected
  124. function DoFunc(Input1, Input2: Single): Single; override;
  125. public
  126. function TestTitle: shortstring; override;
  127. end;
  128. TFloat32MinSpecialTest = class(TFloat32MinTest)
  129. public
  130. constructor Create; override;
  131. function TestTitle: shortstring; override;
  132. end;
  133. TFloat32ImplicitMinSpecialTest = class(TFloat32MinSpecialTest)
  134. protected
  135. function DoFunc(Input1, Input2: Single): Single; override;
  136. public
  137. function TestTitle: shortstring; override;
  138. end;
  139. TFloat32MaxTest = class(TFloat32TwoInputTest)
  140. protected
  141. function DoFunc(Input1, Input2: Single): Single; override;
  142. public
  143. constructor Create; override;
  144. function TestTitle: shortstring; override;
  145. end;
  146. TFloat32ImplicitMaxTest = class(TFloat32MaxTest)
  147. protected
  148. function DoFunc(Input1, Input2: Single): Single; override;
  149. public
  150. function TestTitle: shortstring; override;
  151. end;
  152. TFloat32MaxSpecialTest = class(TFloat32MaxTest)
  153. public
  154. constructor Create; override;
  155. function TestTitle: shortstring; override;
  156. end;
  157. TFloat32ImplicitMaxSpecialTest = class(TFloat32MaxSpecialTest)
  158. protected
  159. function DoFunc(Input1, Input2: Single): Single; override;
  160. public
  161. function TestTitle: shortstring; override;
  162. end;
  163. TFloat32SqrtTest = class(TFloat32OneInputTest)
  164. protected
  165. function DoFunc(Input: Single): Single; override;
  166. public
  167. constructor Create; override;
  168. function TestTitle: shortstring; override;
  169. end;
  170. TFloat32SqrtSpecialTest = class(TFloat32SqrtTest)
  171. public
  172. constructor Create; override;
  173. function TestTitle: shortstring; override;
  174. end;
  175. TFloat32LnTest = class(TFloat32OneInputTest)
  176. protected
  177. function DoFunc(Input: Single): Single; override;
  178. public
  179. constructor Create; override;
  180. function TestTitle: shortstring; override;
  181. end;
  182. TFloat32LnSpecialTest = class(TFloat32LnTest)
  183. public
  184. constructor Create; override;
  185. function TestTitle: shortstring; override;
  186. end;
  187. TFloat32ExpTest = class(TFloat32OneInputTest)
  188. protected
  189. function DoFunc(Input: Single): Single; override;
  190. public
  191. constructor Create; override;
  192. function TestTitle: shortstring; override;
  193. end;
  194. TFloat32ExpSpecialTest = class(TFloat32ExpTest)
  195. public
  196. constructor Create; override;
  197. function TestTitle: shortstring; override;
  198. end;
  199. TFloat32SinTest = class(TFloat32OneInputTest)
  200. protected
  201. function DoFunc(Input: Single): Single; override;
  202. public
  203. constructor Create; override;
  204. function TestTitle: shortstring; override;
  205. end;
  206. TFloat32SinSpecialTest = class(TFloat32SinTest)
  207. public
  208. constructor Create; override;
  209. function TestTitle: shortstring; override;
  210. end;
  211. TFloat32CosTest = class(TFloat32OneInputTest)
  212. protected
  213. function DoFunc(Input: Single): Single; override;
  214. public
  215. constructor Create; override;
  216. function TestTitle: shortstring; override;
  217. end;
  218. TFloat32CosSpecialTest = class(TFloat32CosTest)
  219. public
  220. constructor Create; override;
  221. function TestTitle: shortstring; override;
  222. end;
  223. TFloat32LdexpTest = class(TFloat32FloatIntTest)
  224. protected
  225. function DoFunc(Float: Single; N: Integer): Single; override;
  226. public
  227. constructor Create; override;
  228. function TestTitle: shortstring; override;
  229. end;
  230. TFloat32LdexpSpecialTest = class(TFloat32LdexpTest)
  231. public
  232. constructor Create; override;
  233. function TestTitle: shortstring; override;
  234. end;
  235. { 64-bit floating-point }
  236. TFloat64MinTest = class(TFloat64TwoInputTest)
  237. protected
  238. function DoFunc(Input1, Input2: Double): Double; override;
  239. public
  240. constructor Create; override;
  241. function TestTitle: shortstring; override;
  242. end;
  243. TFloat64ImplicitMinTest = class(TFloat64MinTest)
  244. protected
  245. function DoFunc(Input1, Input2: Double): Double; override;
  246. public
  247. function TestTitle: shortstring; override;
  248. end;
  249. TFloat64MinSpecialTest = class(TFloat64MinTest)
  250. public
  251. constructor Create; override;
  252. function TestTitle: shortstring; override;
  253. end;
  254. TFloat64ImplicitMinSpecialTest = class(TFloat64MinSpecialTest)
  255. protected
  256. function DoFunc(Input1, Input2: Double): Double; override;
  257. public
  258. function TestTitle: shortstring; override;
  259. end;
  260. TFloat64MaxTest = class(TFloat64TwoInputTest)
  261. protected
  262. function DoFunc(Input1, Input2: Double): Double; override;
  263. public
  264. constructor Create; override;
  265. function TestTitle: shortstring; override;
  266. end;
  267. TFloat64ImplicitMaxTest = class(TFloat64MaxTest)
  268. protected
  269. function DoFunc(Input1, Input2: Double): Double; override;
  270. public
  271. function TestTitle: shortstring; override;
  272. end;
  273. TFloat64MaxSpecialTest = class(TFloat64MaxTest)
  274. public
  275. constructor Create; override;
  276. function TestTitle: shortstring; override;
  277. end;
  278. TFloat64ImplicitMaxSpecialTest = class(TFloat64MaxSpecialTest)
  279. protected
  280. function DoFunc(Input1, Input2: Double): Double; override;
  281. public
  282. function TestTitle: shortstring; override;
  283. end;
  284. TFloat64SqrtTest = class(TFloat64OneInputTest)
  285. protected
  286. function DoFunc(Input: Double): Double; override;
  287. public
  288. constructor Create; override;
  289. function TestTitle: shortstring; override;
  290. end;
  291. TFloat64SqrtSpecialTest = class(TFloat64SqrtTest)
  292. public
  293. constructor Create; override;
  294. function TestTitle: shortstring; override;
  295. end;
  296. TFloat64LnTest = class(TFloat64OneInputTest)
  297. protected
  298. function DoFunc(Input: Double): Double; override;
  299. public
  300. constructor Create; override;
  301. function TestTitle: shortstring; override;
  302. end;
  303. TFloat64LnSpecialTest = class(TFloat64LnTest)
  304. public
  305. constructor Create; override;
  306. function TestTitle: shortstring; override;
  307. end;
  308. TFloat64ExpTest = class(TFloat64OneInputTest)
  309. protected
  310. function DoFunc(Input: Double): Double; override;
  311. public
  312. constructor Create; override;
  313. function TestTitle: shortstring; override;
  314. end;
  315. TFloat64ExpSpecialTest = class(TFloat64ExpTest)
  316. public
  317. constructor Create; override;
  318. function TestTitle: shortstring; override;
  319. end;
  320. TFloat64SinTest = class(TFloat64OneInputTest)
  321. protected
  322. function DoFunc(Input: Double): Double; override;
  323. public
  324. constructor Create; override;
  325. function TestTitle: shortstring; override;
  326. end;
  327. TFloat64SinSpecialTest = class(TFloat64SinTest)
  328. public
  329. constructor Create; override;
  330. function TestTitle: shortstring; override;
  331. end;
  332. TFloat64CosTest = class(TFloat64OneInputTest)
  333. protected
  334. function DoFunc(Input: Double): Double; override;
  335. public
  336. constructor Create; override;
  337. function TestTitle: shortstring; override;
  338. end;
  339. TFloat64CosSpecialTest = class(TFloat64CosTest)
  340. public
  341. constructor Create; override;
  342. function TestTitle: shortstring; override;
  343. end;
  344. TFloat64LdexpTest = class(TFloat64FloatIntTest)
  345. protected
  346. function DoFunc(Float: Double; N: Integer): Double; override;
  347. public
  348. constructor Create; override;
  349. function TestTitle: shortstring; override;
  350. end;
  351. TFloat64LdexpSpecialTest = class(TFloat64LdexpTest)
  352. public
  353. constructor Create; override;
  354. function TestTitle: shortstring; override;
  355. end;
  356. { TTestAncestor }
  357. constructor TTestAncestor.Create;
  358. begin
  359. FStartTime := 0;
  360. FEndTime := 0;
  361. FAvgTime := 0;
  362. end;
  363. destructor TTestAncestor.Destroy;
  364. begin
  365. inherited Destroy;
  366. end;
  367. procedure TTestAncestor.SetStartTime;
  368. begin
  369. FStartTime := GetRealTime();
  370. end;
  371. procedure TTestAncestor.SetEndTime;
  372. begin
  373. FEndTime := GetRealTime();
  374. if FEndTime < FStartTime then { Happens if the test runs past midnight }
  375. FEndTime := FEndTime + 86400.0;
  376. end;
  377. procedure TTestAncestor.Run;
  378. var
  379. X: Integer;
  380. begin
  381. SetStartTime;
  382. for X := 0 to ITERATIONS - 1 do
  383. DoTestIteration(X);
  384. SetEndTime;
  385. FAvgTime := FEndTime - FStartTime;
  386. end;
  387. { TFloat32Test }
  388. class function TFloat32Test.IsEqual(Value, Reference: Single): Boolean;
  389. var
  390. Epsilon: Single;
  391. begin
  392. if IsNan(Reference) then
  393. Exit(IsNan(Value))
  394. else if IsInfinite(Reference) then
  395. Exit(Value = Reference) { Must be the same infinity }
  396. else if Abs(Reference) < 0.25 then
  397. Epsilon := 0.00000095367431640625 { 2^-20 ~ 10^-6 }
  398. else
  399. Epsilon := Power(2, Floor(Ln(Reference) / Ln(2)) - 18);
  400. Result := Abs(Value - Reference) <= Epsilon; { If Value is NaN, Result will be set to False }
  401. end;
  402. function TFloat32Test.WriteResults: Boolean;
  403. var
  404. X: Byte;
  405. begin
  406. Result := True;
  407. for X := 0 to High(FResultStorage) do
  408. if not IsEqual(FResultStorage[X], FExpected[X]) then
  409. begin
  410. WriteLn('FAIL - index ', X, '; expected ', FExpected[X], ' got ', FResultStorage[X]);
  411. Result := False;
  412. Exit;
  413. end;
  414. end;
  415. { TFloat32OneInputTest }
  416. procedure TFloat32OneInputTest.DoTestIteration(Iteration: Integer);
  417. begin
  418. Iteration := Iteration and $7;
  419. FResultStorage[Iteration] := DoFunc(FInputs[Iteration]);
  420. end;
  421. { TFloat32TwoInputTest }
  422. procedure TFloat32TwoInputTest.DoTestIteration(Iteration: Integer);
  423. begin
  424. Iteration := Iteration and $7;
  425. FResultStorage[Iteration] := DoFunc(FInputs[Iteration][0], FInputs[Iteration][1]);
  426. end;
  427. { TFloat32FloatIntTest }
  428. procedure TFloat32FloatIntTest.DoTestIteration(Iteration: Integer);
  429. begin
  430. Iteration := Iteration and $7;
  431. FResultStorage[Iteration] := DoFunc(FInputs[Iteration].S, FInputs[Iteration].N);
  432. end;
  433. { TFloat32MinTest }
  434. const
  435. MINMAX_INPUTS: array[0..7] of array[0..1] of Single = (
  436. (-0.5, 0.5),
  437. (1048576.0, 1048577.0),
  438. (-1048576.0, -1048577.0),
  439. (0.0, -0.0),
  440. (0.0, 1E4),
  441. (0.0, -1E4),
  442. (0.0, 1E-4),
  443. (0.0, -1E-4)
  444. );
  445. MIN_EXPECTED: array[0..7] of Single = (
  446. -0.5,
  447. 1048576.0,
  448. -1048577.0,
  449. -0.0,
  450. 0.0,
  451. -1E4,
  452. 0.0,
  453. -1E-4
  454. );
  455. MAX_EXPECTED: array[0..7] of Single = (
  456. 0.5,
  457. 1048577.0,
  458. -1048576.0,
  459. -0.0,
  460. 1E4,
  461. 0.0,
  462. 1E-4,
  463. 0.0
  464. );
  465. constructor TFloat32MinTest.Create;
  466. begin
  467. inherited Create;
  468. Move(MINMAX_INPUTS, FInputs, SizeOf(FInputs));
  469. Move(MIN_EXPECTED, FExpected, SizeOf(FExpected));
  470. end;
  471. function TFloat32MinTest.DoFunc(Input1, Input2: Single): Single;
  472. begin
  473. Result := Min(Input1, Input2);
  474. end;
  475. function TFloat32MinTest.TestTitle: shortstring;
  476. begin
  477. Result := 'Min (single-precision)';
  478. end;
  479. function TFloat32ImplicitMinTest.DoFunc(Input1, Input2: Single): Single;
  480. begin
  481. if Input1 < Input2 then
  482. Result := Input1
  483. else
  484. Result := Input2;
  485. end;
  486. function TFloat32ImplicitMinTest.TestTitle: shortstring;
  487. begin
  488. Result := 'Implicit Min (single-precision)';
  489. end;
  490. { TFloat32MaxTest }
  491. constructor TFloat32MaxTest.Create;
  492. begin
  493. inherited Create;
  494. Move(MINMAX_INPUTS, FInputs, SizeOf(FInputs));
  495. Move(MAX_EXPECTED, FExpected, SizeOf(FExpected));
  496. end;
  497. function TFloat32MaxTest.DoFunc(Input1, Input2: Single): Single;
  498. begin
  499. Result := Max(Input1, Input2);
  500. end;
  501. function TFloat32MaxTest.TestTitle: shortstring;
  502. begin
  503. Result := 'Max (single-precision)';
  504. end;
  505. function TFloat32ImplicitMaxTest.DoFunc(Input1, Input2: Single): Single;
  506. begin
  507. if Input1 > Input2 then
  508. Result := Input1
  509. else
  510. Result := Input2;
  511. end;
  512. function TFloat32ImplicitMaxTest.TestTitle: shortstring;
  513. begin
  514. Result := 'Implicit Max (single-precision)';
  515. end;
  516. { TFloat32MinTest }
  517. const
  518. MINMAX_SPECIAL_INPUTS: array[0..7] of array[0..1] of Single = (
  519. (NaN, 0.0),
  520. (0.0, NaN),
  521. (0.0, Infinity),
  522. (Infinity, 0.0),
  523. (0.0, NegInfinity),
  524. (NegInfinity, 0.0),
  525. (Infinity, NegInfinity),
  526. (NegInfinity, Infinity)
  527. );
  528. MIN_SPECIAL_EXPECTED: array[0..7] of Single = (
  529. 0.0,
  530. NaN,
  531. 0.0,
  532. 0.0,
  533. NegInfinity,
  534. NegInfinity,
  535. NegInfinity,
  536. NegInfinity
  537. );
  538. MAX_SPECIAL_EXPECTED: array[0..7] of Single = (
  539. 0.0,
  540. NaN,
  541. Infinity,
  542. Infinity,
  543. 0.0,
  544. 0.0,
  545. Infinity,
  546. Infinity
  547. );
  548. constructor TFloat32MinSpecialTest.Create;
  549. begin
  550. inherited Create;
  551. Move(MINMAX_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  552. Move(MIN_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  553. end;
  554. function TFloat32MinSpecialTest.TestTitle: shortstring;
  555. begin
  556. Result := 'Min (special single-precision)';
  557. end;
  558. function TFloat32ImplicitMinSpecialTest.DoFunc(Input1, Input2: Single): Single;
  559. begin
  560. if Input1 < Input2 then
  561. Result := Input1
  562. else
  563. Result := Input2;
  564. end;
  565. function TFloat32ImplicitMinSpecialTest.TestTitle: shortstring;
  566. begin
  567. Result := 'Implicit Min (special single-precision)';
  568. end;
  569. { TFloat32MaxTest }
  570. constructor TFloat32MaxSpecialTest.Create;
  571. begin
  572. inherited Create;
  573. Move(MINMAX_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  574. Move(MAX_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  575. end;
  576. function TFloat32MaxSpecialTest.TestTitle: shortstring;
  577. begin
  578. Result := 'Max (special single-precision)';
  579. end;
  580. function TFloat32ImplicitMaxSpecialTest.DoFunc(Input1, Input2: Single): Single;
  581. begin
  582. if Input1 > Input2 then
  583. Result := Input1
  584. else
  585. Result := Input2;
  586. end;
  587. function TFloat32ImplicitMaxSpecialTest.TestTitle: shortstring;
  588. begin
  589. Result := 'Implicit Max (special single-precision)';
  590. end;
  591. { TFloat32SqrtTest }
  592. const
  593. SQRT_INPUTS: array[0..7] of Single = (
  594. 4.0,
  595. 1.0,
  596. 256.0,
  597. 2.0,
  598. 100.0,
  599. 0.5,
  600. 3.1415926535897932384626433832795, { Pi }
  601. 1.5707963267948966192313216916398 { Pi / 2 }
  602. );
  603. SQRT_EXPECTED: array[0..7] of Single = (
  604. 2.0,
  605. 1.0,
  606. 16.0,
  607. 1.414213562373095,
  608. 10.0,
  609. 0.707106781186548,
  610. 1.772453850905516,
  611. 1.253314137315500
  612. );
  613. constructor TFloat32SqrtTest.Create;
  614. begin
  615. inherited Create;
  616. Move(SQRT_INPUTS, FInputs, SizeOf(FInputs));
  617. Move(SQRT_EXPECTED, FExpected, SizeOf(FExpected));
  618. end;
  619. function TFloat32SqrtTest.DoFunc(Input: Single): Single;
  620. begin
  621. Result := Sqrt(Input);
  622. end;
  623. function TFloat32SqrtTest.TestTitle: shortstring;
  624. begin
  625. Result := 'sqrt(x) (single-precision)';
  626. end;
  627. { TFloat32SqrtSpecialTest }
  628. const
  629. SQRT_SPECIAL_INPUTS: array[0..7] of Single = (
  630. 0.0,
  631. Infinity,
  632. NegInfinity,
  633. NaN,
  634. -0.0,
  635. -1.0,
  636. 1E6,
  637. NaN
  638. );
  639. SQRT_SPECIAL_EXPECTED: array[0..7] of Single = (
  640. 0.0,
  641. Infinity,
  642. NaN,
  643. NaN,
  644. 0.0,
  645. NaN,
  646. 1E3,
  647. NaN
  648. );
  649. constructor TFloat32SqrtSpecialTest.Create;
  650. begin
  651. inherited Create;
  652. Move(SQRT_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  653. Move(SQRT_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  654. end;
  655. function TFloat32SqrtSpecialTest.TestTitle: shortstring;
  656. begin
  657. Result := 'sqrt(x) (special single-precision)';
  658. end;
  659. { TFloat32LnTest }
  660. const
  661. LN_EXPECTED: array[0..7] of Single = (
  662. 1.386294361119891,
  663. 0.0,
  664. 5.545177444479562,
  665. 0.693147180559945,
  666. 4.605170185988091,
  667. -0.693147180559945,
  668. 1.1447298858494002,
  669. 0.4515827052894549
  670. );
  671. constructor TFloat32LnTest.Create;
  672. begin
  673. inherited Create;
  674. Move(SQRT_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  675. Move(LN_EXPECTED, FExpected, SizeOf(FExpected));
  676. end;
  677. function TFloat32LnTest.DoFunc(Input: Single): Single;
  678. begin
  679. Result := Ln(Input);
  680. end;
  681. function TFloat32LnTest.TestTitle: shortstring;
  682. begin
  683. Result := 'ln x (single-precision)';
  684. end;
  685. { TFloat32LnSpecialTest }
  686. const
  687. LN_SPECIAL_EXPECTED: array[0..7] of Single = (
  688. NegInfinity,
  689. Infinity,
  690. NaN,
  691. NaN,
  692. NegInfinity,
  693. NaN,
  694. 13.815510557964274,
  695. NaN
  696. );
  697. constructor TFloat32LnSpecialTest.Create;
  698. begin
  699. inherited Create;
  700. Move(SQRT_SPECIAL_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  701. Move(LN_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  702. end;
  703. function TFloat32LnSpecialTest.TestTitle: shortstring;
  704. begin
  705. Result := 'ln x (special single-precision)';
  706. end;
  707. { TFloat32ExpTest }
  708. const
  709. EXP_EXPECTED: array[0..7] of Single = (
  710. 54.598150033144239,
  711. 2.718281828459045,
  712. 1.5114276650041035e+111,
  713. 7.3890560989306502,
  714. 2.6881171418161354e+43,
  715. 1.6487212707001281,
  716. 23.1406926327792690,
  717. 4.8104773809653517
  718. );
  719. constructor TFloat32ExpTest.Create;
  720. begin
  721. inherited Create;
  722. Move(SQRT_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  723. Move(EXP_EXPECTED, FExpected, SizeOf(FExpected));
  724. end;
  725. function TFloat32ExpTest.DoFunc(Input: Single): Single;
  726. begin
  727. Result := Exp(Input);
  728. end;
  729. function TFloat32ExpTest.TestTitle: shortstring;
  730. begin
  731. Result := 'e^x (single-precision)';
  732. end;
  733. { TFloat32ExpSpecialTest }
  734. const
  735. EXP_SPECIAL_EXPECTED: array[0..7] of Single = (
  736. 1.0,
  737. Infinity,
  738. 0,
  739. NaN,
  740. 1.0,
  741. 0.3678794411714423,
  742. Infinity,
  743. NaN
  744. );
  745. constructor TFloat32ExpSpecialTest.Create;
  746. begin
  747. inherited Create;
  748. Move(SQRT_SPECIAL_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  749. Move(EXP_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  750. end;
  751. function TFloat32ExpSpecialTest.TestTitle: shortstring;
  752. begin
  753. Result := 'e^x (special single-precision)';
  754. end;
  755. { TFloat32SinTest }
  756. const
  757. SIN_EXPECTED: array[0..7] of Single = (
  758. -0.756802495307928,
  759. 0.841470984807897,
  760. -0.999208034107063,
  761. 0.9092974268256817,
  762. -0.5063656411097588,
  763. 0.4794255386042030,
  764. 0.0,
  765. 1.0
  766. );
  767. constructor TFloat32SinTest.Create;
  768. begin
  769. inherited Create;
  770. Move(SQRT_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  771. Move(SIN_EXPECTED, FExpected, SizeOf(FExpected));
  772. end;
  773. function TFloat32SinTest.DoFunc(Input: Single): Single;
  774. begin
  775. Result := Sin(Input);
  776. end;
  777. function TFloat32SinTest.TestTitle: shortstring;
  778. begin
  779. Result := 'sin x (single-precision)';
  780. end;
  781. { TFloat32SinSpecialTest }
  782. const
  783. SIN_SPECIAL_INPUTS: array[0..7] of Single = ( { Using different inputs as infinities are invalid }
  784. 0.0,
  785. -1.0,
  786. 1E6,
  787. NaN,
  788. -0.0,
  789. -1.0,
  790. 1E6,
  791. NaN
  792. );
  793. SIN_SPECIAL_EXPECTED: array[0..7] of Single = (
  794. 0.0,
  795. -0.8414709848078965,
  796. -0.3499935021712930,
  797. NaN,
  798. -0.0,
  799. -0.8414709848078965,
  800. -0.3499935021712930,
  801. NaN
  802. );
  803. constructor TFloat32SinSpecialTest.Create;
  804. begin
  805. inherited Create;
  806. Move(SIN_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  807. Move(SIN_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  808. end;
  809. function TFloat32SinSpecialTest.TestTitle: shortstring;
  810. begin
  811. Result := 'sin x (special single-precision)';
  812. end;
  813. { TFloat32CosTest }
  814. const
  815. COS_EXPECTED: array[0..7] of Single = (
  816. -0.6536436208636119,
  817. 0.5403023058681397,
  818. -0.0397907599311577,
  819. -0.4161468365471424,
  820. 0.8623188722876839,
  821. 0.8775825618903727,
  822. -1.0, { Pi }
  823. 0.0
  824. );
  825. constructor TFloat32CosTest.Create;
  826. begin
  827. inherited Create;
  828. Move(SQRT_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  829. Move(COS_EXPECTED, FExpected, SizeOf(FExpected));
  830. end;
  831. function TFloat32CosTest.DoFunc(Input: Single): Single;
  832. begin
  833. Result := Cos(Input);
  834. end;
  835. function TFloat32CosTest.TestTitle: shortstring;
  836. begin
  837. Result := 'cos x (single-precision)';
  838. end;
  839. { TFloat32SinSpecialTest }
  840. const
  841. COS_SPECIAL_EXPECTED: array[0..7] of Single = (
  842. 1.0,
  843. 0.5403023058681397,
  844. 0.9367521275331448,
  845. NaN,
  846. 1.0,
  847. 0.5403023058681397,
  848. 0.9367521275331448,
  849. NaN
  850. );
  851. constructor TFloat32CosSpecialTest.Create;
  852. begin
  853. inherited Create;
  854. Move(SIN_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  855. Move(COS_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  856. end;
  857. function TFloat32CosSpecialTest.TestTitle: shortstring;
  858. begin
  859. Result := 'cos x (special single-precision)';
  860. end;
  861. { TFloat32LdexpTest }
  862. const
  863. LDEXP_INPUTS: array[0..7] of TSingleIntPair = (
  864. (S: 1.0; N: 0),
  865. (S: 2.7182818284590452353602874713527; N: -1),
  866. (S: 0.85309609426787873559547283129472; N: 6),
  867. (S: 0.1; N: 1),
  868. (S: 0.2; N: 2),
  869. (S: 0.3; N: 3),
  870. (S: 0.4; N: 4),
  871. (S: 0.5; N: 5)
  872. );
  873. LDEXP_EXPECTED: array[0..7] of Single = (
  874. 1.0,
  875. 1.3591409142295226176801437356763,
  876. 54.598150033144239078110261202862,
  877. 0.2,
  878. 0.8,
  879. 2.4,
  880. 6.4,
  881. 16.0
  882. );
  883. constructor TFloat32LdexpTest.Create;
  884. begin
  885. inherited Create;
  886. Move(LDEXP_INPUTS, FInputs, SizeOf(FInputs));
  887. Move(LDEXP_EXPECTED, FExpected, SizeOf(FExpected));
  888. end;
  889. function TFloat32LdexpTest.DoFunc(Float: Single; N: Integer): Single;
  890. begin
  891. Result := LdExp(Float, N);
  892. end;
  893. function TFloat32LdexpTest.TestTitle: shortstring;
  894. begin
  895. Result := 'ldexp(x, n) (single-precision)';
  896. end;
  897. { TFloat32SpecialLdexpTest }
  898. const
  899. LDEXP_SPECIAL_INPUTS: array[0..7] of TSingleIntPair = (
  900. (S: Infinity; N: 0),
  901. (S: NegInfinity; N: 0),
  902. (S: 2.0; N: -128),
  903. (S: 2.0; N: 127),
  904. (S: NaN; N: 1),
  905. (S: 0.0; N: 16384),
  906. (S: 1.7014118346046923173168730371588e+38; N: -128),
  907. (S: 2.9387358770557187699218413430556e-39; N: 127)
  908. );
  909. LDEXP_SPECIAL_EXPECTED: array[0..7] of Single = (
  910. Infinity,
  911. NegInfinity,
  912. 2.9387358770557187699218413430556e-39,
  913. Infinity,
  914. Nan,
  915. 0.0,
  916. 0.5,
  917. 0.5
  918. );
  919. constructor TFloat32LdexpSpecialTest.Create;
  920. begin
  921. inherited Create;
  922. Move(LDEXP_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  923. Move(LDEXP_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  924. end;
  925. function TFloat32LdexpSpecialTest.TestTitle: shortstring;
  926. begin
  927. Result := 'ldexp(x, n) (special single-precision)';
  928. end;
  929. { TFloat64Test }
  930. class function TFloat64Test.IsEqual(Value, Reference: Double): Boolean;
  931. var
  932. Epsilon: Double;
  933. begin
  934. if IsNan(Reference) then
  935. Exit(IsNan(Value))
  936. else if IsInfinite(Reference) then
  937. Exit(Value = Reference)
  938. else if Abs(Reference) < 0.25 then
  939. Epsilon := 9.094947017729282379150390625e-13 { 2^-40 ~ 10^-12 }
  940. else
  941. Epsilon := Power(2, Floor(Ln(Reference) / Ln(2)) - 18);
  942. Result := Abs(Value - Reference) <= Epsilon;
  943. end;
  944. function TFloat64Test.WriteResults: Boolean;
  945. var
  946. X: Byte;
  947. begin
  948. Result := True;
  949. for X := 0 to High(FResultStorage) do
  950. if not IsEqual(FResultStorage[X], FExpected[X]) then
  951. begin
  952. WriteLn('FAIL - index ', X, '; expected ', FExpected[X], ' got ', FResultStorage[X]);
  953. Result := False;
  954. Exit;
  955. end;
  956. end;
  957. { TFloat64OneInputTest }
  958. procedure TFloat64OneInputTest.DoTestIteration(Iteration: Integer);
  959. begin
  960. Iteration := Iteration and $7;
  961. FResultStorage[Iteration] := DoFunc(FInputs[Iteration]);
  962. end;
  963. { TFloat64TwoInputTest }
  964. procedure TFloat64TwoInputTest.DoTestIteration(Iteration: Integer);
  965. begin
  966. Iteration := Iteration and $7;
  967. FResultStorage[Iteration] := DoFunc(FInputs[Iteration][0], FInputs[Iteration][1]);
  968. end;
  969. { TFloat64FloatIntTest }
  970. procedure TFloat64FloatIntTest.DoTestIteration(Iteration: Integer);
  971. begin
  972. Iteration := Iteration and $7;
  973. FResultStorage[Iteration] := DoFunc(FInputs[Iteration].D, FInputs[Iteration].N);
  974. end;
  975. { TFloat64MinTest }
  976. const
  977. MINMAX_64_INPUTS: array[0..7] of array[0..1] of Double = (
  978. (-0.5, 0.5),
  979. (1048576.0, 1048577.0),
  980. (-1048576.0, -1048577.0),
  981. (0.0, -0.0),
  982. (0.0, 1E4),
  983. (0.0, -1E4),
  984. (0.0, 1E-4),
  985. (0.0, -1E-4)
  986. );
  987. MIN_64_EXPECTED: array[0..7] of Double = (
  988. -0.5,
  989. 1048576.0,
  990. -1048577.0,
  991. -0.0,
  992. 0.0,
  993. -1E4,
  994. 0.0,
  995. -1E-4
  996. );
  997. MAX_64_EXPECTED: array[0..7] of Double = (
  998. 0.5,
  999. 1048577.0,
  1000. -1048576.0,
  1001. -0.0,
  1002. 1E4,
  1003. 0.0,
  1004. 1E-4,
  1005. 0.0
  1006. );
  1007. constructor TFloat64MinTest.Create;
  1008. begin
  1009. inherited Create;
  1010. Move(MINMAX_64_INPUTS, FInputs, SizeOf(FInputs));
  1011. Move(MIN_64_EXPECTED, FExpected, SizeOf(FExpected));
  1012. end;
  1013. function TFloat64MinTest.DoFunc(Input1, Input2: Double): Double;
  1014. begin
  1015. Result := Min(Input1, Input2);
  1016. end;
  1017. function TFloat64MinTest.TestTitle: shortstring;
  1018. begin
  1019. Result := 'Min (double-precision)';
  1020. end;
  1021. function TFloat64ImplicitMinTest.DoFunc(Input1, Input2: Double): Double;
  1022. begin
  1023. if Input1 < Input2 then
  1024. Result := Input1
  1025. else
  1026. Result := Input2;
  1027. end;
  1028. function TFloat64ImplicitMinTest.TestTitle: shortstring;
  1029. begin
  1030. Result := 'Implicit Min (double-precision)';
  1031. end;
  1032. { TFloat64MaxTest }
  1033. constructor TFloat64MaxTest.Create;
  1034. begin
  1035. inherited Create;
  1036. Move(MINMAX_64_INPUTS, FInputs, SizeOf(FInputs));
  1037. Move(MAX_64_EXPECTED, FExpected, SizeOf(FExpected));
  1038. end;
  1039. function TFloat64MaxTest.DoFunc(Input1, Input2: Double): Double;
  1040. begin
  1041. Result := Max(Input1, Input2);
  1042. end;
  1043. function TFloat64MaxTest.TestTitle: shortstring;
  1044. begin
  1045. Result := 'Max (double-precision)';
  1046. end;
  1047. function TFloat64ImplicitMaxTest.DoFunc(Input1, Input2: Double): Double;
  1048. begin
  1049. if Input1 > Input2 then
  1050. Result := Input1
  1051. else
  1052. Result := Input2;
  1053. end;
  1054. function TFloat64ImplicitMaxTest.TestTitle: shortstring;
  1055. begin
  1056. Result := 'Implicit Max (double-precision)';
  1057. end;
  1058. { TFloat64MinTest }
  1059. const
  1060. MINMAX_64_SPECIAL_INPUTS: array[0..7] of array[0..1] of Double = (
  1061. (NaN, 0.0),
  1062. (0.0, NaN),
  1063. (0.0, Infinity),
  1064. (Infinity, 0.0),
  1065. (0.0, NegInfinity),
  1066. (NegInfinity, 0.0),
  1067. (Infinity, NegInfinity),
  1068. (NegInfinity, Infinity)
  1069. );
  1070. MIN_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1071. 0.0,
  1072. NaN,
  1073. 0.0,
  1074. 0.0,
  1075. NegInfinity,
  1076. NegInfinity,
  1077. NegInfinity,
  1078. NegInfinity
  1079. );
  1080. MAX_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1081. 0.0,
  1082. NaN,
  1083. Infinity,
  1084. Infinity,
  1085. 0.0,
  1086. 0.0,
  1087. Infinity,
  1088. Infinity
  1089. );
  1090. constructor TFloat64MinSpecialTest.Create;
  1091. begin
  1092. inherited Create;
  1093. Move(MINMAX_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  1094. Move(MIN_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1095. end;
  1096. function TFloat64MinSpecialTest.TestTitle: shortstring;
  1097. begin
  1098. Result := 'Min (special double-precision)';
  1099. end;
  1100. function TFloat64ImplicitMinSpecialTest.DoFunc(Input1, Input2: Double): Double;
  1101. begin
  1102. if Input1 < Input2 then
  1103. Result := Input1
  1104. else
  1105. Result := Input2;
  1106. end;
  1107. function TFloat64ImplicitMinSpecialTest.TestTitle: shortstring;
  1108. begin
  1109. Result := 'Implicit Min (special double-precision)';
  1110. end;
  1111. { TFloat64MaxTest }
  1112. constructor TFloat64MaxSpecialTest.Create;
  1113. begin
  1114. inherited Create;
  1115. Move(MINMAX_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  1116. Move(MAX_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1117. end;
  1118. function TFloat64MaxSpecialTest.TestTitle: shortstring;
  1119. begin
  1120. Result := 'Max (special double-precision)';
  1121. end;
  1122. function TFloat64ImplicitMaxSpecialTest.DoFunc(Input1, Input2: Double): Double;
  1123. begin
  1124. if Input1 > Input2 then
  1125. Result := Input1
  1126. else
  1127. Result := Input2;
  1128. end;
  1129. function TFloat64ImplicitMaxSpecialTest.TestTitle: shortstring;
  1130. begin
  1131. Result := 'Implicit Max (special double-precision)';
  1132. end;
  1133. { TFloat64SqrtTest }
  1134. const
  1135. SQRT_64_INPUTS: array[0..7] of Double = (
  1136. 4.0,
  1137. 1.0,
  1138. 256.0,
  1139. 2.0,
  1140. 100.0,
  1141. 0.5,
  1142. 3.1415926535897932384626433832795, { Pi }
  1143. 1.5707963267948966192313216916398 { Pi / 2 }
  1144. );
  1145. SQRT_64_EXPECTED: array[0..7] of Double = (
  1146. 2.0,
  1147. 1.0,
  1148. 16.0,
  1149. 1.4142135623730950488016887242097,
  1150. 10.0,
  1151. 0.70710678118654752440084436210485,
  1152. 1.7724538509055160272981674833411,
  1153. 1.2533141373155002512078826424055
  1154. );
  1155. constructor TFloat64SqrtTest.Create;
  1156. begin
  1157. inherited Create;
  1158. Move(SQRT_64_INPUTS, FInputs, SizeOf(FInputs));
  1159. Move(SQRT_64_EXPECTED, FExpected, SizeOf(FExpected));
  1160. end;
  1161. function TFloat64SqrtTest.DoFunc(Input: Double): Double;
  1162. begin
  1163. Result := Sqrt(Input);
  1164. end;
  1165. function TFloat64SqrtTest.TestTitle: shortstring;
  1166. begin
  1167. Result := 'sqrt(x) (double-precision)';
  1168. end;
  1169. { TFloat64SqrtSpecialTest }
  1170. const
  1171. SQRT_64_SPECIAL_INPUTS: array[0..7] of Double = (
  1172. 0.0,
  1173. Infinity,
  1174. NegInfinity,
  1175. NaN,
  1176. -0.0,
  1177. -1.0,
  1178. 1E6,
  1179. NaN
  1180. );
  1181. SQRT_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1182. 0.0,
  1183. Infinity,
  1184. NaN,
  1185. NaN,
  1186. 0.0,
  1187. NaN,
  1188. 1E3,
  1189. NaN
  1190. );
  1191. constructor TFloat64SqrtSpecialTest.Create;
  1192. begin
  1193. inherited Create;
  1194. Move(SQRT_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  1195. Move(SQRT_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1196. end;
  1197. function TFloat64SqrtSpecialTest.TestTitle: shortstring;
  1198. begin
  1199. Result := 'sqrt(x) (special double-precision)';
  1200. end;
  1201. { TFloat64LnTest }
  1202. const
  1203. LN_64_EXPECTED: array[0..7] of Double = (
  1204. 1.3862943611198906188344642429164,
  1205. 0.0,
  1206. 5.5451774444795624753378569716654,
  1207. 0.69314718055994530941723212145818,
  1208. 4.6051701859880913680359829093687,
  1209. -0.69314718055994530941723212145818,
  1210. 1.1447298858494001741434273513531,
  1211. 0.45158270528945486472619522989488
  1212. );
  1213. constructor TFloat64LnTest.Create;
  1214. begin
  1215. inherited Create;
  1216. Move(SQRT_64_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  1217. Move(LN_64_EXPECTED, FExpected, SizeOf(FExpected));
  1218. end;
  1219. function TFloat64LnTest.DoFunc(Input: Double): Double;
  1220. begin
  1221. Result := Ln(Input);
  1222. end;
  1223. function TFloat64LnTest.TestTitle: shortstring;
  1224. begin
  1225. Result := 'ln x (double-precision)';
  1226. end;
  1227. { TFloat64LnSpecialTest }
  1228. const
  1229. LN_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1230. NegInfinity,
  1231. Infinity,
  1232. NaN,
  1233. NaN,
  1234. NegInfinity,
  1235. NaN,
  1236. 13.815510557964274104107948728106,
  1237. NaN
  1238. );
  1239. constructor TFloat64LnSpecialTest.Create;
  1240. begin
  1241. inherited Create;
  1242. Move(SQRT_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  1243. Move(LN_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1244. end;
  1245. function TFloat64LnSpecialTest.TestTitle: shortstring;
  1246. begin
  1247. Result := 'ln x (special double-precision)';
  1248. end;
  1249. { TFloat64ExpTest }
  1250. const
  1251. EXP_64_EXPECTED: array[0..7] of Double = (
  1252. 54.598150033144239078110261202861,
  1253. 2.7182818284590455, // remove the last 5 and append 2353602874713527 (too precise),
  1254. 1.5114276650041035425200896657073e+111,
  1255. 7.389056098930650227230427460575,
  1256. 2.68811714181613544841262555158e+43,
  1257. 1.6487212707001281468486507878142,
  1258. 23.140692632779269005729086367949,
  1259. 4.8104773809653516554730356667038
  1260. );
  1261. constructor TFloat64ExpTest.Create;
  1262. begin
  1263. inherited Create;
  1264. Move(SQRT_64_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  1265. Move(EXP_64_EXPECTED, FExpected, SizeOf(FExpected));
  1266. end;
  1267. function TFloat64ExpTest.DoFunc(Input: Double): Double;
  1268. begin
  1269. Result := Exp(Input);
  1270. end;
  1271. function TFloat64ExpTest.TestTitle: shortstring;
  1272. begin
  1273. Result := 'e^x (double-precision)';
  1274. end;
  1275. { TFloat64ExpSpecialTest }
  1276. const
  1277. EXP_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1278. 1.0,
  1279. Infinity,
  1280. 0,
  1281. NaN,
  1282. 1.0,
  1283. 0.36787944117144232159552377016146,
  1284. Infinity,
  1285. NaN
  1286. );
  1287. constructor TFloat64ExpSpecialTest.Create;
  1288. begin
  1289. inherited Create;
  1290. Move(SQRT_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  1291. Move(EXP_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1292. end;
  1293. function TFloat64ExpSpecialTest.TestTitle: shortstring;
  1294. begin
  1295. Result := 'e^x (special double-precision)';
  1296. end;
  1297. { TFloat64SinTest }
  1298. const
  1299. SIN_64_EXPECTED: array[0..7] of Double = (
  1300. -0.75680249530792825137263909451183,
  1301. 0.8414709848078965066525023216303,
  1302. -0.99920803410706269906759056238387,
  1303. 0.90929742682568169539601986591174,
  1304. -0.50636564110975879365655761045979,
  1305. 0.47942553860420300027328793521557,
  1306. 0.0,
  1307. 1.0
  1308. );
  1309. constructor TFloat64SinTest.Create;
  1310. begin
  1311. inherited Create;
  1312. Move(SQRT_64_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  1313. Move(SIN_64_EXPECTED, FExpected, SizeOf(FExpected));
  1314. end;
  1315. function TFloat64SinTest.DoFunc(Input: Double): Double;
  1316. begin
  1317. Result := Sin(Input);
  1318. end;
  1319. function TFloat64SinTest.TestTitle: shortstring;
  1320. begin
  1321. Result := 'sin x (single-precision)';
  1322. end;
  1323. { TFloat64SinSpecialTest }
  1324. const
  1325. SIN_64_SPECIAL_INPUTS: array[0..7] of Double = ( { Using different inputs as infinities are invalid }
  1326. 0.0,
  1327. -1.0,
  1328. 1E6,
  1329. NaN,
  1330. -0.0,
  1331. -1.0,
  1332. 1E6,
  1333. NaN
  1334. );
  1335. SIN_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1336. 0.0,
  1337. -0.8414709848078965066525023216303,
  1338. -0.34999350217129295211765248678077,
  1339. NaN,
  1340. -0.0,
  1341. -0.8414709848078965066525023216303,
  1342. -0.34999350217129295211765248678077,
  1343. NaN
  1344. );
  1345. constructor TFloat64SinSpecialTest.Create;
  1346. begin
  1347. inherited Create;
  1348. Move(SIN_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  1349. Move(SIN_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1350. end;
  1351. function TFloat64SinSpecialTest.TestTitle: shortstring;
  1352. begin
  1353. Result := 'sin x (double single-precision)';
  1354. end;
  1355. { TFloat64CosTest }
  1356. const
  1357. COS_64_EXPECTED: array[0..7] of Double = (
  1358. -0.65364362086361191463916818309775,
  1359. 0.54030230586813971740093660744298,
  1360. -0.03979075993115770952448155799687,
  1361. -0.41614683654714238699756822950076,
  1362. 0.86231887228768393410193851395084,
  1363. 0.87758256189037271611628158260383,
  1364. -1.0, { Pi }
  1365. 0.0
  1366. );
  1367. constructor TFloat64CosTest.Create;
  1368. begin
  1369. inherited Create;
  1370. Move(SQRT_64_INPUTS, FInputs, SizeOf(FInputs)); { Reuse the sqrt inputs }
  1371. Move(COS_64_EXPECTED, FExpected, SizeOf(FExpected));
  1372. end;
  1373. function TFloat64CosTest.DoFunc(Input: Double): Double;
  1374. begin
  1375. Result := Cos(Input);
  1376. end;
  1377. function TFloat64CosTest.TestTitle: shortstring;
  1378. begin
  1379. Result := 'cos x (double-precision)';
  1380. end;
  1381. { TFloat64CosSpecialTest }
  1382. const
  1383. COS_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1384. 1.0,
  1385. 0.54030230586813971740093660744298,
  1386. 0.93675212753314478693853253507492,
  1387. NaN,
  1388. 1.0,
  1389. 0.54030230586813971740093660744298,
  1390. 0.93675212753314478693853253507492,
  1391. NaN
  1392. );
  1393. constructor TFloat64CosSpecialTest.Create;
  1394. begin
  1395. inherited Create;
  1396. Move(SIN_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  1397. Move(COS_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1398. end;
  1399. function TFloat64CosSpecialTest.TestTitle: shortstring;
  1400. begin
  1401. Result := 'cos x (special double-precision)';
  1402. end;
  1403. { TFloat64LdexpTest }
  1404. const
  1405. LDEXP_64_INPUTS: array[0..7] of TDoubleIntPair = (
  1406. (D: 1.0; N: 0),
  1407. (D: 2.7182818284590452353602874713527; N: -1),
  1408. (D: 0.85309609426787873559547283129472; N: 6),
  1409. (D: 0.1; N: 1),
  1410. (D: 0.2; N: 2),
  1411. (D: 0.3; N: 3),
  1412. (D: 0.4; N: 4),
  1413. (D: 0.5; N: 5)
  1414. );
  1415. LDEXP_64_EXPECTED: array[0..7] of Double = (
  1416. 1.0,
  1417. 1.3591409142295226176801437356763,
  1418. 54.598150033144239078110261202862,
  1419. 0.2,
  1420. 0.8,
  1421. 2.4,
  1422. 6.4,
  1423. 16.0
  1424. );
  1425. constructor TFloat64LdexpTest.Create;
  1426. begin
  1427. inherited Create;
  1428. Move(LDEXP_64_INPUTS, FInputs, SizeOf(FInputs));
  1429. Move(LDEXP_64_EXPECTED, FExpected, SizeOf(FExpected));
  1430. end;
  1431. function TFloat64LdexpTest.DoFunc(Float: Double; N: Integer): Double;
  1432. begin
  1433. Result := LdExp(Float, N);
  1434. end;
  1435. function TFloat64LdexpTest.TestTitle: shortstring;
  1436. begin
  1437. Result := 'ldexp(x, n) (double-precision)';
  1438. end;
  1439. { TFloat32SpecialLdexpTest }
  1440. const
  1441. LDEXP_64_SPECIAL_INPUTS: array[0..7] of TDoubleIntPair = (
  1442. (D: Infinity; N: 0),
  1443. (D: NegInfinity; N: 0),
  1444. (D: 2.0; N: -1024),
  1445. (D: 2.0; N: 1023),
  1446. (D: NaN; N: 1),
  1447. (D: 0.0; N: 16384),
  1448. (D: 8.9884656743115795386465259539451e+307; N: -1024),
  1449. (D: 5.562684646268003457725581793331e-309; N: 1023)
  1450. );
  1451. LDEXP_64_SPECIAL_EXPECTED: array[0..7] of Double = (
  1452. Infinity,
  1453. NegInfinity,
  1454. 5.562684646268003457725581793331e-309,
  1455. Infinity,
  1456. Nan,
  1457. 0.0,
  1458. 0.5,
  1459. 0.5
  1460. );
  1461. constructor TFloat64LdexpSpecialTest.Create;
  1462. begin
  1463. inherited Create;
  1464. Move(LDEXP_64_SPECIAL_INPUTS, FInputs, SizeOf(FInputs));
  1465. Move(LDEXP_64_SPECIAL_EXPECTED, FExpected, SizeOf(FExpected));
  1466. end;
  1467. function TFloat64LdexpSpecialTest.TestTitle: shortstring;
  1468. begin
  1469. Result := 'ldexp(x, n) (special double-precision)';
  1470. end;
  1471. { Main function }
  1472. const
  1473. { TCompleteByteRange and descendants }
  1474. TestClasses: array[0..39] of TTestClass = (
  1475. TFloat32MinTest,
  1476. TFloat32MaxTest,
  1477. TFloat32ImplicitMinTest,
  1478. TFloat32ImplicitMaxTest,
  1479. TFloat32MinSpecialTest,
  1480. TFloat32MaxSpecialTest,
  1481. TFloat32ImplicitMinSpecialTest,
  1482. TFloat32ImplicitMaxSpecialTest,
  1483. TFloat32SqrtTest,
  1484. TFloat32SqrtSpecialTest,
  1485. TFloat32LnTest,
  1486. TFloat32LnSpecialTest,
  1487. TFloat32ExpTest,
  1488. TFloat32ExpSpecialTest,
  1489. TFloat32SinTest,
  1490. TFloat32SinSpecialTest,
  1491. TFloat32CosTest,
  1492. TFloat32CosSpecialTest,
  1493. TFloat32LdexpTest,
  1494. TFloat32LdexpSpecialTest,
  1495. TFloat64MinTest,
  1496. TFloat64MaxTest,
  1497. TFloat64ImplicitMinTest,
  1498. TFloat64ImplicitMaxTest,
  1499. TFloat64MinSpecialTest,
  1500. TFloat64MaxSpecialTest,
  1501. TFloat64ImplicitMinSpecialTest,
  1502. TFloat64ImplicitMaxSpecialTest,
  1503. TFloat64SqrtTest,
  1504. TFloat64SqrtSpecialTest,
  1505. TFloat64LnTest,
  1506. TFloat64LnSpecialTest,
  1507. TFloat64ExpTest,
  1508. TFloat64ExpSpecialTest,
  1509. TFloat64SinTest,
  1510. TFloat64SinSpecialTest,
  1511. TFloat64CosTest,
  1512. TFloat64CosSpecialTest,
  1513. TFloat64LdexpTest,
  1514. TFloat64LdexpSpecialTest
  1515. );
  1516. var
  1517. CurrentObject: TTestAncestor;
  1518. Failed: Boolean;
  1519. X: Integer;
  1520. SummedUpAverageDuration, AverageDuration : Double;
  1521. begin
  1522. SetExceptionMask(GetExceptionMask + [exOverflow, exZeroDivide, exInvalidOp]);
  1523. SummedUpAverageDuration := 0.0;
  1524. Failed := False;
  1525. WriteLn('Floating-point compilation and timing test');
  1526. WriteLn('------------------------------------------');
  1527. for X := low(TestClasses) to High(TestClasses) do
  1528. begin
  1529. try
  1530. CurrentObject := TestClasses[X].Create;
  1531. try
  1532. Write(CurrentObject.TestTitle:40, ' - ');
  1533. CurrentObject.Run;
  1534. if CurrentObject.WriteResults then
  1535. begin
  1536. AverageDuration := ((CurrentObject.RunTime * 1000000000.0) / ITERATIONS);
  1537. WriteLn('Pass - average iteration duration: ', AverageDuration:1:3, ' ns');
  1538. SummedUpAverageDuration := SummedUpAverageDuration + AverageDuration;
  1539. end
  1540. else
  1541. { Final average isn't processed if a test failed, so there's no need
  1542. to calculate and add the average duration to it }
  1543. Failed := True;
  1544. finally
  1545. CurrentObject.Free;
  1546. end;
  1547. except on E: Exception do
  1548. begin
  1549. WriteLn('Exception "', E.ClassName, '" raised while running test object of class "', TestClasses[X].ClassName, '"');
  1550. Failed := True;
  1551. end;
  1552. end;
  1553. end;
  1554. if Failed then
  1555. Halt(1);
  1556. WriteLn(#10'ok');
  1557. WriteLn('- Sum of average durations: ', SummedUpAverageDuration:1:3, ' ns');
  1558. WriteLn('- Overall average duration: ', (SummedUpAverageDuration / Length(TestClasses)):1:3, ' ns');
  1559. end.