Post by Robert PrinsPost by Bob MastaOn Sun, 29 Mar 2015 21:52:27 +0000, Robert Prins
Post by Robert PrinsI've managed to remove part of the code that deals with doubles, the original
code would calculate
km * 6.0 / time
and print the resulting double. I've now changed that into
using the upper 32 bits of
((km * 600 / time + 5) * 3435973837) shr 3,
which, through reciprocal multiplication (3435973837 = 2^35 / 10), gives me 10
times the velocity, properly truncated and that is passed to a routine that
prints integers.
I am missing the point of the reciprocal multiplication.
If you are looking for 10 times the velocity, rounded to the
nearest integer (ie nearest 10th of the raw velocity),
int(10 * km * 600 / time + 0.5)
where int() truncates without rounding?
What am I missing?
As I already said...
However, some further thought about your simple solution led me to change my code to
push 0 // placeholder for dtv.v as longint
cmp dword ptr [esi + offset dtv.time], 0
fild dword ptr [esi + offset dtv.km]
fmul d_6v0
fidiv dword ptr [esi + offset dtv.time]
fst qword ptr [esi + offset dtv.v] // I (still) need the double
fmul d_10v0
fadd d_0v5
{$ifdef sse3}
db $db,$0c,$24 // fisttp dword [esp] VP doesn't have fisttp
{$else}
call System._Trunc
mov [esp], eax
{$endif}
And that is even better and shorter than what I had. Happy bunny!
I finally solved the problem, the Pascal output files still the ones coming from
PL/I, and I've managed to get rid of the (slow) float-to-string conversion
routine from the RTL, replacing it with the integer-to-string version. For those
interested:
Common:
const d_rmul: array[0..2] of double = (1.0, 10.0, 100.0);
const d_radd: array[0..2] of double = (0.5, 0.05, 0.005);
var _line : string[255];
var print : string[19];
The "print_2_line" procedure just concatenates the contents of "print" to
"_line" and adds ' | '.
Original Pascal:
procedure add_double_2_line(var _double: double; _i, _j: longint);
var _d: double;
begin
_d:= _double;
str(frac(_double * d_rmul[_j]):6:4, print);
if print[3] >= '5' then
_d:= _double + d_radd[_j];
str(_d:_i:_j, print);
add_print_2_line;
end; {add_double_2_line}
Original assembler:
procedure add_double_2_line(var _double: double; _i, _j: longint); assembler;
{&uses none} {&frame-}
asm
//a-in add_double_2_line
mov eax, _double
mov edx, _i
fld qword ptr [eax]
mov eax, _j
fld st
fmul qword ptr d_rmul[eax * 8]
fld st
push ecx
fisttp dword [esp]
fild dword ptr [esp]
fsubp st(1), st
pop ecx
push 6
push 4
push offset print
push type print - 1
call System._StrFlt
cmp byte ptr print[3], "5"
jb @01
fadd qword ptr d_radd[eax * 8]
@01:
movzx ecx, byte ptr _line
push edx // _i
add edx, 3
add byte ptr _line, dl
add ecx, offset _line
push eax // _j
push ecx
push type _line - 1
call System._StrFlt
mov byte ptr [ecx], " "
mov dword ptr [ecx + edx - 2], " ³ "
//a-out
end; {add_double_2_line}
Current routine:
procedure add_double_2_line(var _double: double; _i, _j: longint); assembler;
{&uses none} {&frame+}
asm
//a-in add_double_2_line
mov eax, _double
fld qword ptr [eax]
fld st
// if (trunc(frac(_d * d_rmul[_j]) * 10000 + 0.5) >= 5000) and
// (trunc(frac(_d * d_rmul[_j]) * 10000 + 0.5) < 10000) then
mov ecx, _j
fmul qword ptr d_rmul[ecx * 8]
fld st
push eax
db $db,$0c,$24 // fisttp dword [esp]
fild dword ptr [esp]
fsubp st(1),st
fmul d_10000v0
fadd d_0v5
db $db,$0c,$24 // fisttp dword [esp]
pop eax
cmp eax, 5000
jl @01
cmp eax, 10000
jge @01
// _d:= _d + d_radd[_j]
fadd qword ptr d_radd[ecx * 8]
@01:
fmul qword ptr d_rmul[ecx * 8]
fadd d_0v5
push eax // value to be printed
db $db,$0c,$24 // fisttp dword [esp]
mov edx, _i
push edx // width
movzx eax, byte ptr _line
add edx, 3
add byte ptr _line, dl
add eax, offset _line
push eax // position in _line
push type _line - 1 // length of receiving field, big enough
call System._StrInt
mov byte ptr [eax], " " // blank out length set by StrInt
mov dword ptr [edx + eax - 2], " | "
test ecx, ecx // no further processing if rounded to 0 decimals
jz @03
// The following code moves the value one position to the left and
// adds a decimal point, and converts blanks into significant zeros
neg ecx
lea ecx, [ecx + edx - 3]
@02:
mov dl, [eax + 1]
mov [eax], dl
inc eax
dec ecx
jnz @02
mov byte ptr [eax], "."
or dword ptr [eax - 1], $00300030 // "#0 0 #0 0"
@03:
//a-out
end; {add_double_2_line}
Still not entirely happy about it, especially the small loop at the end, but
given that at most 5 characters have to be moved, soit...
Robert
--
Robert AH Prins
robert(a)prino(d)org
No programming @ http://hitchwiki.org/prino/