Byte swapping
Question
Does anyone have the algorithms for swapping bytes between big-endian and
little-endian format.
Answer
A:
Check the function swap in Delphi Help. There is a typo in their definition,
the correct one is:
function Swap(X) : word;
Their example is as follows:
var
X: Word;
begin
X := Swap($1234); { $3412 }
end;
Swap will provide a big-endian when you feed it with a little-endian and
viceversa.
A:
To swap a 16-bit integer or word, use
value: integer;
value := swap(value); {builtin Pascal function}
To swap a 32-bit long, use
value: longint;
value := swap(value shr 16) or (longint(swap(value and $ffff)) shl 16);
I don't know what the standards are for floating point values, but if they
conform to integer and longint (my guess is they do), then you'd use (for
double):
value: double;
block: array[0..7] of byte absolute value;
temp: byte;
for i := 0 to 3 do begin
temp := block[i];
block[i] := block[7-i];
block[7-i] := temp;
end;
If you're using real, array should be 0..5 and the for loop 0 to 2; if
you're using comp, 0..7 and 0 to 3; for single, 0..3 and 0 to 1; for
extended, 0..9 and 0 to 4.
You can also change this to a procedure that takes a pointer to the value
and the size of the value, eg. (this is off the top of my head, may need
tweaking):
procedure swapper (valin: pointer; size: integer);
var
i: integer;
temp: byte;
val: ^byte;
begin
size := size - 1;
val := valin;
for i := 0 to (size div 2) do begin
temp := val[i];
val[i] := val[size-i];
val[size-i] := temp;
end;
end;
then you can call this using
swapper (@value, sizeof(value));
(This would also work for longint, integer, etc. but swap() is more efficient.)
Note that in addition to swapping the bytes, you may have to do a format
conversion (from eg. Microsoft floating point to ANSI); I don't dabble in
floating point, so I don't know for sure. Best thing might be to flip the
bytes and see if the other system recognizes it as the same number that
Delphi does.
A:
I had a similar problem, I was reading a TColor from disk, in RGB
format ($RRGGBB), while delphi uses BGR format.
I solved my problem by and'ing the initial number with a mask, and
retrieving the values, and then placing them into my format. eg:
color := $F03200;
r := (color and $FF0000) div $010000; {should return $F0}
g := (color and $00FF00) div $000100; {should return $32}
b := (color and $0000FF); {should return $00}
newcolor := (b * $010000) + (g * $000100) + b;
If this works, newcolor should hold $0032F0.
A:
You will probably have to use an assembly routine something like...
var
result : byte;
asm {
mov cx,8
mov ah,0
mov al,
@do_loop
shr al,1
shl ah,1
jcc @dont_set_bit ; jump carry clear (I'm not sure if this is correct)
xor ah,1
@dont_set_bit:
loop do_loop
mov result,al
}
This is more like pseudo-code (because my assembly's a little rusty). =
If you want it to be more "portable" then you'd have to use pascal =
instead of inline assembly (you can still use SHL - bit-wise shift left =
and SHR - right).
Encryption Algorithm
Question
I would like a Delphi unit algorithm that I can compile in... not those
external DLL, 'C' source etc.
I realize that home-brewed algorithms can be relatively weak.... but
can someone just send me some algorithms to start with?
Answer
A:
const
C1 = 52845; {Used for encryption of Master Password string}
C2 = 11719;
Key = 1234;
{ Standard Decryption algorithm - Copied from Borland}
function Decrypt(const S: String; Key: Word): String;
var
I: byte;
begin
Result[0] := S[0];
for I := 1 to Length(S) do begin
Result[I] := char(byte(S[I]) xor (Key shr 8));
Key := (byte(S[I]) + Key) * C1 + C2;
end;
end;
{ Standard Encryption algorithm - Copied from Borland}
function Encrypt(const S: String; Key: Word): String;
Var
I: byte;
begin
Result[0] := S[0];
for I := 1 to Length(S) do begin
Result[I] := char(byte(S[I]) xor (Key shr 8));
Key := (byte(Result[I]) + Key) * C1 + C2;
end;
end;
Random Number Generator
Question
Does anyone know of a way to improve the random number generator in
Delphi? The generator used in Delphi is pretty much the same as
that in VB or C.
Answer
A:
Following is an assembler version of a random number generator
which I got from Dr Dobbs Journal or one of the other magazines
several years ago. Try it and see if it gives you any better results.
function __R( range : word ) : word; assembler;
asm
mov ax, Word(System.RandSeed) { DS:[003eH] }
mov bx, Word(System.RandSeed+2) { DS:[0040H] }
mov cx, ax
mul CS:word ptr [0598H]
shl cx, 1
shl cx, 1
shl cx, 1
add ch, cl
add dx, cx
add dx, bx
shl bx, 1
shl bx, 1
add dx, bx
add dh, bl
mov cx, 0005H
@1:
shl bx, 1
loop @1
add dh, bl
add ax, 0001
adc dx, 0000
mov word(System.RandSeed), ax { [003eH], ax }
mov word(System.RandSeed+2), dx { [0040H], dx }
xor ax, ax
mov bx, range
or bx, bx
je @2
xchg dx, ax
div bx
xchg dx, ax
@2:
end;
Duplicating the atan2 function in Delphi
Question
How to program the atan2 function?
Answer
function sgn (a : real) : real;
begin
if a < 0 then sgn := -1;
else sgn := 1;
end;
function atan2 (y, x : real) : real;
begin
if x > 0 then atan2 := arctan (y/x)
else if x < 0 then atan2 := arctan (y/x) + pi
else atan2 := pi/2 * sgn (y);
end;
{
I did this a while ago when moving from FORTRAN to Pascal.
I think I tested it way back then but my memory is fading
good luck.
}
Nathan
-------------------------------------------------------------------------------
From: Terje Mathisen
Subject: Re: How to duplicate C function ATAN2 in Delphi?
Date: 18 May 1995 19:25:10 GMT
I think you should seriously consider using the FPATAN instruction for this!
This x87 opcode implements an IEEE-compliant ATAN2() function, with full extended
precision, and the hardware will handle all the special cases for you.
If you have numeric exceptions enabled, and input bogus values, the x87 chip will
raise the appropriate signal, without the need for upfront testing of parameters.
A BP/TP/Delphi-compatible version would look like this:
Function atan2(y : extended; x : extended): Extended;
Assembler;
asm
fld [y]
fld [x]
fpatan
end;
Total execution time is less than 200 cycles on a Pentium, with less than 1 ulp
maximum error, unless you have a Pentium with the FDIV bug, where it could fail
almost anywhere after the first 15-20 OK bits! :-)
The library function ArcTan(x) is implemented as fpatan(1.0,x), as long as you
compile with IEEE reals {$N+} set.
Terje
--
-Terje Mathisen (include std disclaimer)
"almost all programming can be viewed as an exercise in caching"
-------------------------------------------------------------------------------
This is a potential problem as the win87em.dll or the sw
lib does not work with this so the sw will fail on all non
CoP equipped boxes.
--
Name: Dr Jon Jenkins
Internet: jenkinsj@ozy.dec.com
Calculating periodic debt payments
Question
How to calculate periodic debt payments?
Answer
PAYMENT()
Returns the periodic amount required to repay a debt.
function payment(princ, int, term: double): double;
var temp: double;
begin
int := int / 100;
temp := exp(ln(int + 1) * term);
result := princ * ((int * temp) / (temp - 1));
end;
Syntax
PAYMENT(, , )
The original amount to be repaid over time.
The interest rate per period expressed as a positive decimal
number. Specify the interest rate in the same time increment
as the term. It is to be expressed as a percentage. The
number is divided by 100 inside the function.
The number of payments. Specify the term in the same time
increment as the interest.
Description
Use PAYMENT(#) to calculate the periodic amount (payment)
required to repay a loan or investment of
amount in payments. PAYMENT(#) returns a numeric
value based on a fixed interest rate compounding over a fixed
length of time. If is positive, PAYMENT(#)
returns a positive number. If is negative,
PAYMENT(#) returns a negative number. Express the interest
rate as a decimal. For example, if the annual interest rate is
9.5%, is 9.5 for payments made annually.
Express and in the same time
increment. For example, if the payments are monthly, express
the interest rate per month, and the number of payments in
months. You would express an annual interest rate of#9.5%, for
example, as 9.5/12, which is the 9.5% divided by 12#months.
The formula used to calculate PAYMENT(#) is as follows:
term
int*(1 + int)^
pmt = princ * -------------------
term
(1 + int)^ - 1
where int = rate / 100 (as a percentage).
For the monthly payment required to repay a principal amount of
$16860.68 in five years, at 9% interest, the formula expressed
as a dBASE expression looks like this:
MyVar := PAYMENT(16860.68, 9/12, 60) {Returns 350.00}
DISCLAIMER: You have the right to use this technical information
subject to the terms of the No-Nonsense License Statement that
you received with the Borland product to which this information
pertains.