<HTML>
I've done some speed and accuracy comparisons between our respective Frac functions. Initially, my "SafeFrac" was marginally faster than "FracDoSkip", but I managed to optimise Thorsten's routine a little bit into the following:<br>
<br>
function FracSkip2(const X: ValReal): ValReal; assembler; nostackframe;<br>
asm<br>
align 16<br>
movq rax, xmm0<br>
shr rax, 48<br>
and ax, $7FF0<br>
cmp ax, $4330<br>
jge @@zero<br>
cmp ax, $3FE0<br>
jbe @@skip<br>
cvttsd2si rax, xmm0<br>
cvtsi2sd xmm4, rax<br>
subsd xmm0, xmm4<br>
ret<br>
@@zero:<br>
xorpd xmm0, xmm0<br>
@@skip:<br>
end;<br>
<br>
My test compared Frac, FracDoSkip, SafeFrac and what I call FracSkip2 above, which reworks the comparisons to use only 16 bits, and replaces "jmp @@skip" with "ret". The results are as follows (as you can see... all of them are a great improvement over Frac). Frac raises SIGFPE if plus or minus infinity is passed in, but our functions return zero. This may or may not be a desirable change.<br>
<br>
Code sizes (alignment will round it up to the nearest 16 bytes): Frac = 49 bytes, FracDoSkip = 52 bytes, SafeFrac = 46 bytes, FracSkip2 = 45 bytes.<br>
<br>
Long story short, with a few tweaks, Thorsten's routine is the fastest and also the smallest.<br>
<br>
****<br>
<br>
My test set was:<br>
<br>
DataSet: array[0..14] of Double = (1.5, 0, 2251799813685248, 4503599627370496, 1E300, 0.125, 3.6415926535897932384626433832795, -1.5, -2251799813685248, -4503599627370496, -1E300, -0.125, -3.6415926535897932384626433832795, Infinity, NegInfinity);<br>
<br>
For each value, it is tested as is, then DataSet[X] + 0.5, then DataSet[X] - 0.5 (best way to determine how it handles precision without it being optimised out by the compiler).<br>
<br>
****<br>
<br>
Frac( 1.5000000000000000E+000) = 5.0000000000000000E-001 - Pass - Time = 124.483 ns<br>
FracDoSkip( 1.5000000000000000E+000) = 5.0000000000000000E-001 - Pass - Time = 47.525 ns<br>
SafeFrac( 1.5000000000000000E+000) = 5.0000000000000000E-001 - Pass - Time = 32.707 ns<br>
FracSkip2( 1.5000000000000000E+000) = 5.0000000000000000E-001 - Pass - Time = 34.904 ns<br>
Frac( 2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 126.170 ns<br>
FracDoSkip( 2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 51.210 ns<br>
SafeFrac( 2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 35.351 ns<br>
FracSkip2( 2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 33.911 ns<br>
Frac( 1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 125.927 ns<br>
FracDoSkip( 1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 49.127 ns<br>
SafeFrac( 1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 34.695 ns<br>
FracSkip2( 1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 36.139 ns<br>
Frac( 0.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 119.800 ns<br>
FracDoSkip( 0.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 40.316 ns<br>
SafeFrac( 0.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 35.875 ns<br>
FracSkip2( 0.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 34.046 ns<br>
Frac( 5.0000000000000000E-001) = 5.0000000000000000E-001 - Pass - Time = 118.913 ns<br>
FracDoSkip( 5.0000000000000000E-001) = 5.0000000000000000E-001 - Pass - Time = 40.183 ns<br>
SafeFrac( 5.0000000000000000E-001) = 5.0000000000000000E-001 - Pass - Time = 36.783 ns<br>
FracSkip2( 5.0000000000000000E-001) = 5.0000000000000000E-001 - Pass - Time = 34.976 ns<br>
Frac(-5.0000000000000000E-001) = -5.0000000000000000E-001 - Pass - Time = 127.560 ns<br>
FracDoSkip(-5.0000000000000000E-001) = -5.0000000000000000E-001 - Pass - Time = 41.676 ns<br>
SafeFrac(-5.0000000000000000E-001) = -5.0000000000000000E-001 - Pass - Time = 36.577 ns<br>
FracSkip2(-5.0000000000000000E-001) = -5.0000000000000000E-001 - Pass - Time = 34.714 ns<br>
Frac( 2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 126.323 ns<br>
FracDoSkip( 2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 49.108 ns<br>
SafeFrac( 2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 35.376 ns<br>
FracSkip2( 2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 36.373 ns<br>
Frac( 2.2517998136852485E+015) = 5.0000000000000000E-001 - Pass - Time = 131.001 ns<br>
FracDoSkip( 2.2517998136852485E+015) = 5.0000000000000000E-001 - Pass - Time = 54.474 ns<br>
SafeFrac( 2.2517998136852485E+015) = 5.0000000000000000E-001 - Pass - Time = 38.834 ns<br>
FracSkip2( 2.2517998136852485E+015) = 5.0000000000000000E-001 - Pass - Time = 37.139 ns<br>
Frac( 2.2517998136852475E+015) = 5.0000000000000000E-001 - Pass - Time = 131.932 ns<br>
FracDoSkip( 2.2517998136852475E+015) = 5.0000000000000000E-001 - Pass - Time = 52.214 ns<br>
SafeFrac( 2.2517998136852475E+015) = 5.0000000000000000E-001 - Pass - Time = 37.093 ns<br>
FracSkip2( 2.2517998136852475E+015) = 5.0000000000000000E-001 - Pass - Time = 35.674 ns<br>
Frac( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 82.749 ns<br>
FracDoSkip( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 38.613 ns<br>
SafeFrac( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 38.575 ns<br>
FracSkip2( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 33.970 ns<br>
Frac( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 86.126 ns<br>
FracDoSkip( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 38.434 ns<br>
SafeFrac( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 38.636 ns<br>
FracSkip2( 4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 33.747 ns<br>
Frac( 4.5035996273704955E+015) = 5.0000000000000000E-001 - Pass - Time = 131.589 ns<br>
FracDoSkip( 4.5035996273704955E+015) = 5.0000000000000000E-001 - Pass - Time = 53.594 ns<br>
SafeFrac( 4.5035996273704955E+015) = 5.0000000000000000E-001 - Pass - Time = 36.617 ns<br>
FracSkip2( 4.5035996273704955E+015) = 5.0000000000000000E-001 - Pass - Time = 36.509 ns<br>
Frac( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 82.875 ns<br>
FracDoSkip( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 39.008 ns<br>
SafeFrac( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 39.112 ns<br>
FracSkip2( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 34.195 ns<br>
Frac( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 85.401 ns<br>
FracDoSkip( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 38.653 ns<br>
SafeFrac( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 38.655 ns<br>
FracSkip2( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 34.408 ns<br>
Frac( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 84.719 ns<br>
FracDoSkip( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 39.174 ns<br>
SafeFrac( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 38.876 ns<br>
FracSkip2( 1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 33.570 ns<br>
Frac( 1.2500000000000000E-001) = 1.2500000000000000E-001 - Pass - Time = 123.770 ns<br>
FracDoSkip( 1.2500000000000000E-001) = 1.2500000000000000E-001 - Pass - Time = 41.642 ns<br>
SafeFrac( 1.2500000000000000E-001) = 1.2500000000000000E-001 - Pass - Time = 38.704 ns<br>
FracSkip2( 1.2500000000000000E-001) = 1.2500000000000000E-001 - Pass - Time = 35.399 ns<br>
Frac( 6.2500000000000000E-001) = 6.2500000000000000E-001 - Pass - Time = 128.967 ns<br>
FracDoSkip( 6.2500000000000000E-001) = 6.2500000000000000E-001 - Pass - Time = 42.082 ns<br>
SafeFrac( 6.2500000000000000E-001) = 6.2500000000000000E-001 - Pass - Time = 38.199 ns<br>
FracSkip2( 6.2500000000000000E-001) = 6.2500000000000000E-001 - Pass - Time = 36.072 ns<br>
Frac(-3.7500000000000000E-001) = -3.7500000000000000E-001 - Pass - Time = 128.962 ns<br>
FracDoSkip(-3.7500000000000000E-001) = -3.7500000000000000E-001 - Pass - Time = 40.375 ns<br>
SafeFrac(-3.7500000000000000E-001) = -3.7500000000000000E-001 - Pass - Time = 37.153 ns<br>
FracSkip2(-3.7500000000000000E-001) = -3.7500000000000000E-001 - Pass - Time = 34.515 ns<br>
Frac( 3.6415926535897931E+000) = 6.4159265358979312E-001 - Pass - Time = 129.245 ns<br>
FracDoSkip( 3.6415926535897931E+000) = 6.4159265358979312E-001 - Pass - Time = 53.440 ns<br>
SafeFrac( 3.6415926535897931E+000) = 6.4159265358979312E-001 - Pass - Time = 38.390 ns<br>
FracSkip2( 3.6415926535897931E+000) = 6.4159265358979312E-001 - Pass - Time = 36.963 ns<br>
Frac( 4.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 132.623 ns<br>
FracDoSkip( 4.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 52.325 ns<br>
SafeFrac( 4.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 39.016 ns<br>
FracSkip2( 4.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 36.818 ns<br>
Frac( 3.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 128.032 ns<br>
FracDoSkip( 3.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 49.834 ns<br>
SafeFrac( 3.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 37.077 ns<br>
FracSkip2( 3.1415926535897931E+000) = 1.4159265358979312E-001 - Pass - Time = 37.099 ns<br>
Frac(-1.5000000000000000E+000) = -5.0000000000000000E-001 - Pass - Time = 132.057 ns<br>
FracDoSkip(-1.5000000000000000E+000) = -5.0000000000000000E-001 - Pass - Time = 53.112 ns<br>
SafeFrac(-1.5000000000000000E+000) = -5.0000000000000000E-001 - Pass - Time = 38.287 ns<br>
FracSkip2(-1.5000000000000000E+000) = -5.0000000000000000E-001 - Pass - Time = 36.849 ns<br>
Frac(-1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 130.452 ns<br>
FracDoSkip(-1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 51.451 ns<br>
SafeFrac(-1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 36.993 ns<br>
FracSkip2(-1.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 36.110 ns<br>
Frac(-2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 131.912 ns<br>
FracDoSkip(-2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 52.946 ns<br>
SafeFrac(-2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 38.330 ns<br>
FracSkip2(-2.0000000000000000E+000) = 0.0000000000000000E+000 - Pass - Time = 37.156 ns<br>
Frac(-2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 131.354 ns<br>
FracDoSkip(-2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 53.712 ns<br>
SafeFrac(-2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 36.978 ns<br>
FracSkip2(-2.2517998136852480E+015) = 0.0000000000000000E+000 - Pass - Time = 36.262 ns<br>
Frac(-2.2517998136852475E+015) = -5.0000000000000000E-001 - Pass - Time = 127.641 ns<br>
FracDoSkip(-2.2517998136852475E+015) = -5.0000000000000000E-001 - Pass - Time = 52.853 ns<br>
SafeFrac(-2.2517998136852475E+015) = -5.0000000000000000E-001 - Pass - Time = 38.318 ns<br>
FracSkip2(-2.2517998136852475E+015) = -5.0000000000000000E-001 - Pass - Time = 37.286 ns<br>
Frac(-2.2517998136852485E+015) = -5.0000000000000000E-001 - Pass - Time = 130.918 ns<br>
FracDoSkip(-2.2517998136852485E+015) = -5.0000000000000000E-001 - Pass - Time = 52.916 ns<br>
SafeFrac(-2.2517998136852485E+015) = -5.0000000000000000E-001 - Pass - Time = 37.928 ns<br>
FracSkip2(-2.2517998136852485E+015) = -5.0000000000000000E-001 - Pass - Time = 36.701 ns<br>
Frac(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 82.714 ns<br>
FracDoSkip(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 37.410 ns<br>
SafeFrac(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 37.091 ns<br>
FracSkip2(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 33.130 ns<br>
Frac(-4.5035996273704955E+015) = -5.0000000000000000E-001 - Pass - Time = 131.699 ns<br>
FracDoSkip(-4.5035996273704955E+015) = -5.0000000000000000E-001 - Pass - Time = 52.932 ns<br>
SafeFrac(-4.5035996273704955E+015) = -5.0000000000000000E-001 - Pass - Time = 38.499 ns<br>
FracSkip2(-4.5035996273704955E+015) = -5.0000000000000000E-001 - Pass - Time = 37.341 ns<br>
Frac(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 85.069 ns<br>
FracDoSkip(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 38.384 ns<br>
SafeFrac(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 39.041 ns<br>
FracSkip2(-4.5035996273704960E+015) = 0.0000000000000000E+000 - Pass - Time = 34.266 ns<br>
Frac(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 81.913 ns<br>
FracDoSkip(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 37.216 ns<br>
SafeFrac(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 37.385 ns<br>
FracSkip2(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 34.328 ns<br>
Frac(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 85.317 ns<br>
FracDoSkip(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 38.639 ns<br>
SafeFrac(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 38.644 ns<br>
FracSkip2(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 34.293 ns<br>
Frac(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 85.878 ns<br>
FracDoSkip(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 38.932 ns<br>
SafeFrac(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 38.651 ns<br>
FracSkip2(-1.0000000000000001E+300) = 0.0000000000000000E+000 - Pass - Time = 34.316 ns<br>
Frac(-1.2500000000000000E-001) = -1.2500000000000000E-001 - Pass - Time = 128.603 ns<br>
FracDoSkip(-1.2500000000000000E-001) = -1.2500000000000000E-001 - Pass - Time = 41.592 ns<br>
SafeFrac(-1.2500000000000000E-001) = -1.2500000000000000E-001 - Pass - Time = 37.280 ns<br>
FracSkip2(-1.2500000000000000E-001) = -1.2500000000000000E-001 - Pass - Time = 34.995 ns<br>
Frac( 3.7500000000000000E-001) = 3.7500000000000000E-001 - Pass - Time = 124.473 ns<br>
FracDoSkip( 3.7500000000000000E-001) = 3.7500000000000000E-001 - Pass - Time = 42.099 ns<br>
SafeFrac( 3.7500000000000000E-001) = 3.7500000000000000E-001 - Pass - Time = 38.716 ns<br>
FracSkip2( 3.7500000000000000E-001) = 3.7500000000000000E-001 - Pass - Time = 36.194 ns<br>
Frac(-6.2500000000000000E-001) = -6.2500000000000000E-001 - Pass - Time = 129.138 ns<br>
FracDoSkip(-6.2500000000000000E-001) = -6.2500000000000000E-001 - Pass - Time = 42.219 ns<br>
SafeFrac(-6.2500000000000000E-001) = -6.2500000000000000E-001 - Pass - Time = 39.724 ns<br>
FracSkip2(-6.2500000000000000E-001) = -6.2500000000000000E-001 - Pass - Time = 34.307 ns<br>
Frac(-3.6415926535897931E+000) = -6.4159265358979312E-001 - Pass - Time = 129.833 ns<br>
FracDoSkip(-3.6415926535897931E+000) = -6.4159265358979312E-001 - Pass - Time = 51.274 ns<br>
SafeFrac(-3.6415926535897931E+000) = -6.4159265358979312E-001 - Pass - Time = 38.494 ns<br>
FracSkip2(-3.6415926535897931E+000) = -6.4159265358979312E-001 - Pass - Time = 37.459 ns<br>
Frac(-3.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 132.230 ns<br>
FracDoSkip(-3.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 53.066 ns<br>
SafeFrac(-3.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 38.658 ns<br>
FracSkip2(-3.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 36.351 ns<br>
Frac(-4.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 126.783 ns<br>
FracDoSkip(-4.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 51.889 ns<br>
SafeFrac(-4.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 38.785 ns<br>
FracSkip2(-4.1415926535897931E+000) = -1.4159265358979312E-001 - Pass - Time = 36.711 ns<br>
Frac(+Inf) = EXCEPTION - EInvalidOp raised with message "Invalid floating point operation"<br>
FracDoSkip(+Inf) = 0.0000000000000000E+000 - Pass - Time = 39.849 ns<br>
SafeFrac(+Inf) = 0.0000000000000000E+000 - Pass - Time = 38.889 ns<br>
FracSkip2(+Inf) = 0.0000000000000000E+000 - Pass - Time = 34.289 ns<br>
Frac(+Inf) = EXCEPTION - EInvalidOp raised with message "Invalid floating point operation"<br>
FracDoSkip(+Inf) = 0.0000000000000000E+000 - Pass - Time = 40.781 ns<br>
SafeFrac(+Inf) = 0.0000000000000000E+000 - Pass - Time = 37.504 ns<br>
FracSkip2(+Inf) = 0.0000000000000000E+000 - Pass - Time = 33.043 ns<br>
Frac(+Inf) = EXCEPTION - EInvalidOp raised with message "Invalid floating point operation"<br>
FracDoSkip(+Inf) = 0.0000000000000000E+000 - Pass - Time = 40.993 ns<br>
SafeFrac(+Inf) = 0.0000000000000000E+000 - Pass - Time = 39.575 ns<br>
FracSkip2(+Inf) = 0.0000000000000000E+000 - Pass - Time = 33.041 ns<br>
Frac(-Inf) = EXCEPTION - EInvalidOp raised with message "Invalid floating point operation"<br>
FracDoSkip(-Inf) = 0.0000000000000000E+000 - Pass - Time = 40.414 ns<br>
SafeFrac(-Inf) = 0.0000000000000000E+000 - Pass - Time = 37.835 ns<br>
FracSkip2(-Inf) = 0.0000000000000000E+000 - Pass - Time = 33.294 ns<br>
Frac(-Inf) = EXCEPTION - EInvalidOp raised with message "Invalid floating point operation"<br>
FracDoSkip(-Inf) = 0.0000000000000000E+000 - Pass - Time = 39.871 ns<br>
SafeFrac(-Inf) = 0.0000000000000000E+000 - Pass - Time = 37.885 ns<br>
FracSkip2(-Inf) = 0.0000000000000000E+000 - Pass - Time = 34.041 ns<br>
Frac(-Inf) = EXCEPTION - EInvalidOp raised with message "Invalid floating point operation"<br>
FracDoSkip(-Inf) = 0.0000000000000000E+000 - Pass - Time = 40.437 ns<br>
SafeFrac(-Inf) = 0.0000000000000000E+000 - Pass - Time = 38.868 ns<br>
FracSkip2(-Inf) = 0.0000000000000000E+000 - Pass - Time = 33.819 ns<br>
<br>
****<br>
<br>
Gareth aka. Kit<br>
</HTML>