Convert an Octal number to Decimal and Hexadecimal - delphi

I am writing a program that converts an Octal number to Decimal and Hexadecimal. I wrote a function called OctToInt.
function OctToInt(Value: string): Longint;
var
i: Integer;
int: Integer;
begin
int := 0;
for i := 0 to Length(Value) do
begin
int := int * 8 + StrToInt(Copy(Value, i, 1));
end;
Result := int;
end;
I call this function in this way:
var oct:integer;
begin
oct:=OctToInt(Edit13.Text);
Edit15.Text:=IntToStr(oct);
end;
When I type 34 (Octal) the decimal number should be 28 but the program gives me 220. Do you know why?
Also, do you have any idea about a converter OctToHex?

You have to change the start of "your" for with 1.
function OctToInt(Value: string): Longint;
var
i: Integer;
int: Integer;
begin
int := 0;
for i := 1 to Length(Value) do //here you need 1, not 0
begin
int := int * 8 + StrToInt(Copy(Value, i, 1));
end;
Result := int;
end;
The conversion Octal-Hexadecimal could be hard to do, so I suggest you another way:
EditHexadecimal.Text:=(IntToHex(StrToInt(EditInteger.Text),8));
As you can see here, with this code the EditHexadecimal is the Edit where you put the hexadecimal number. With that line I convert a number from decimal to hexadecimal.
You already have the decimal number because you get it with the function OctToInt, so you don't need more code.

This code accepts a string with a base-8 representation of an integer, and returns the corresponding integer:
function IntPower(const N, k: integer): integer;
var
i: Integer;
begin
result := 1;
for i := 1 to k do
result := result * N;
end;
function OctToInt(const Value: string): integer;
var
i: integer;
begin
result := 0;
for i := 1 to Length(Value) do
inc(result, StrToInt(Value[i]) * IntPower(8, Length(Value) - i));
end;
When it comes to converting an integer to a hexadecimal string representation, you already have IntToHex.

i made this formula so you can process octals in batches of 3-digits at a time - it's been tested from 000 through 777 to perfectly generate the decimal integer from octals :
if your octals are in a variable oct and temp placeholder o2
then
(37 < oct % 100)*8 + int(0.08*(oct-(o2=oct%10))+0.7017)*8 + o2
if you wanna further streamline that without the placeholder, then its
(37 < oct%100)*8 + int(0.7017+0.08*(oct-(oct%=10)))*8 + oct
the "0.7017" is possibly sin(-10*π/8) or 1/sqrt(2), or just 2^(1/-2), but since i found the formula via regression i'm not 100% sure on this.
Another fast trick is that if all 3 digits are the same number - 222 333 555 etc, simply take the first digit then multiply by 73 (cuz 73 in octal is 111). The sequence chain of multipliers for 2-6 consecutive matching digits are
9, 73, 585, 4681, 37449
(it also happens that within this list, for each x,
one of {x-2,x+0,x+2} is prime

Related

How to print code128C?

I am trying to print a code128C (numbers only) but I believe that the way of sending the data is incorrect ... at the time of reading the code the conversion does not result in the data initially informed.
In code128A I submit an ASCCI code, the printer converts to hex and print...the reader convert it back to ASCII.
In code128C if I submit an ASCCI, at the time of reading the reader converts to decimal, which does not result in the initial value.
EX:
128A Input: '1' Printer: 31 Reading: 1
128C Input: '1' Printer: 31 Reading: 49
I imagine that I should submit the input code already in integer .... but as the command is composed of other information I do not know how to send it in integer.
This is the code of code128A:
ComandoAnsiString := tp.cod128A('12'); //Data entry
function TTP650.cod128A(cod: AnsiString): AnsiString;
begin
// Fill out the CODE 128 printing protocol
Result := #29+#107+#73 + chr(length(cod)+2) + #123+#65 + cod;
end;
WritePrinter( HandleImp, PAnsiChar(ComandoAnsiString), Length(ComandoAnsiString),
CaracteresImpressos); //send to printer
This is the code I've been trying with code128C:
ComandoAnsiString := tp.cod128C('12');
function TTP650.cod128C(cod: AnsiString): AnsiString;
begin
Result := #29+#107+#73 + chr(length(cod)+2) + #123+#67 + cod;
end;
WritePrinter( HandleImp, PAnsiChar(ComandoAnsiString), Length(ComandoAnsiString),
CaracteresImpressos);
I'm dealing with a thermal printer and one codebar reader simple, default.
The sending codes(WritePrinter) are from the library WinSpool ... the rest are codes written by me.
Important code information is on pages 47 to 50 of the guide.
Guide
Assuming users will enter the wanted barcodes as a string of digits which may be stored somewhere as string and at the time of printing, passed to the printing function as human readable string.
The printing function will then convert to an array of bytes, packing the digits according to CODE C (each pair of two decimal digits, forming a value 00..99, stored in a byte). Iow, if the entry string of digits is e.g. '123456', then this is represented by three bytes with values 12, 34, 56.
function cod128C(const cod: string): TBytes;
const
GS = 29; // GS - Print bar code
k = 107; // k - -"-
m = 73; // m - CODE128
CS = 123; // { - select code set //}
CC = 67; // C - CODE C
var
i, len, n, x: integer;
s: string;
begin
len := Length(cod);
if len = 0 then exit;
// raise for odd number of digits in cod, ...
// if Odd(len) then
// raise Exception.Create('cod must have even number of digits');
s := cod;
// ... alternatively assume a preceeding zero digit before the first digit
// in cod
if Odd(len) then
begin
s := '0'+s;
inc(len);
end;
len := len div 2; // we pack 2 digits into one byte
SetLength(result, 6 + len);
result[0] := GS;
result[1] := k;
result[2] := m;
result[3] := 2 + len; // length of cod, + 2 for following code set selector
result[4] := CS;
result[5] := CC;
n := length(s);
i := 1; // index to S
x := 6; // index to result
while i < n do
begin
result[x] := StrToInt(MidStr(s, i, 2));
inc(i, 2);
inc(x, 1);
end;
end;
And with a form with a button, edit and memo you can test the function and send it to your printer with the following.
procedure TForm1.Button1Click(Sender: TObject);
var
cmnd: TBytes;
i: integer;
s: string;
begin
cmnd := cod128C(Edit1.Text);
for i := 0 to Length(cmnd)-1 do
s := s+IntToStr(cmnd[i])+', ';
Memo1.Lines.Add(s);
WritePrinter( HandleImp, #cmnd[0], Length(cmnd), CaracteresImpressos);
end;
You may want to add a check for only decimal digits in the input string, but I leave that to you.

How do I convert a `string` of `integers` in `hexadecimal` (and back)?

I want to convert a string of integers in hexadecimal (and the opposite).
I've seen the IntToHex functions, but it uses a small integer.
For example, I need to convert the number:
999888777666555444 in hexadecimal
and then the opposite:
hexadecimal number in 999888777666555444
If you need to convert more than 8-bytes values, you can represent your very-long-integer as array of byte, word, dword or something. In that case you should just convert any particular item and concatenate results. Opposite is the same (only thing you should remember is value should be considered as right-aligned).
converting a arbitrary length buffer to hex:
function HexDump(const _Buffer; _Len: integer): string;
type
PByte = ^Byte;
var
i: integer;
p: PByte;
begin
p := #_Buffer;
Result := '';
for i := 0 to _Len - 1 do begin
Result := Result + Long2Hex2(p^);
Inc(p);
end;
end;
And the utility functions used by this:
const
/// <summary>
/// String containing all characters that can be used as digits
/// </summary>
DIGIT_CHARS: string = '0123456789ABCDEFGHIJKlMNOPQRSTUVWXYZ';
function Long2Num(_l: ULong; _Base: Byte; _MinWidth: Integer = 1): string;
var
m: Byte;
begin
Result := '';
while _l > 0 do begin
m := _l mod _Base;
_l := _l div _Base;
Result := DIGIT_CHARS[m + 1] + Result;
end;
while Length(Result) < _MinWidth do
Result := '0' + Result;
end;
function Long2Hex(_l: ULong): string;
begin
Result := Long2Num(_l, 16);
end;
function Long2Hex2(_l: ULong): string;
begin
Result := Long2Hex(_l);
if Length(Result) < 2 then
Result := '0' + Result;
end;
These functions are part of my dzlib.
Note: This does not generate the hex numbers as you might expect them, e.g. if you pass an integer to the function like this:
var
IntValue: integer;
begin
IntValue := $12345678;
s := HexDump(IntValue, SizeOf(IntValue));
end;
You end up with s = '78563412' because Intel processors store integers in little endian format.
Unfortunately the other way round is more difficult, because there is no standard arbitrary length integer type in Delphi. There are some implementations of such a type though.

Delphi - Random Combination (Math)

I have a BIG problem here and do not even know how to start...
In short explanation, I need to know if a number is in a set of results from a random combination...
Let me explain better: I created a random "number" with 3 integer chars from 1 to 8, like this:
procedure TForm1.btn1Click(Sender: TObject);
var
cTmp: Char;
sTmp: String[3];
begin
sTmp := '';
While (Length(sTmp) < 3) Do
Begin
Randomize;
cTmp := IntToStr(Random(7) + 1)[1];
If (Pos(cTmp, sTmp) = 0) Then
sTmp := sTmp + cTmp;
end;
edt1.Text := sTmp;
end;
Now I need to know is some other random number, let's say "324" (example), is in the set of results of that random combination.
Please, someone can help? A link to get the equations to solve this problem will be enough...
Ok, let me try to add some useful information:
Please, first check this link https://en.wikipedia.org/wiki/Combination
Once I get some number typed by user, in an editbox, I need to check if it is in the set of this random combination: S = (1..8) and k = 3
Tricky, hum?
Here is what I got. Maybe it be usefull for someone in the future. Thank you for all people that tried to help!
Function IsNumOnSet(const Min, Max, Num: Integer): Boolean;
var
X, Y, Z: Integer;
Begin
Result := False;
For X := Min to Max Do
For Y := Min to Max Do
For Z := Min to Max Do
If (X <> Y) and (X <> Z) and (Y <> Z) Then
If (X * 100 + Y * 10 + Z = Num) Then
Begin
Result := True;
Exit;
end;
end;
You want to test whether something is a combination. To do this you need to verify that the putative combination satisfies the following conditions:
Each element is in the range 1..N and
No element appears more than once.
So, implement it like this.
Declare an array of counts, say array [1..N] of Integer. If N varies at runtime you will need a dynamic array.
Initialise all members of the array to zero.
Loop through each element of the putative combination. Check that the element is in the range 1..N. And increment the count for that element.
If any element has a count greater than 1 then this is not a valid combination.
Now you can simplify by replacing the array of integers with an array of booleans but that should be self evident.
You have your generator. Once your value is built, do something like
function isValidCode( Digits : Array of Char; Value : String ) : Boolean;
var
nI : Integer;
begin
for nI := 0 to High(Digits) do
begin
result := Pos(Digits[nI], Value ) > 0;
if not result then break;
end;
end;
Call like this...
isValidCode(["3","2","4"], RandomValue);
Note : it works only because you have unique digits, the digit 3 is only once in you final number. For something more generic, you'll have to tweak this function. (testing "3","3","2" would return true but it would be false !)
UPDATED :
I dislike the nested loop ^^. Here is a function that return the nTh digit of an integer. It will return -1 if the digits do not exists. :
function TForm1.getDigits(value : integer; ndigits : Integer ) : Integer;
var
base : Integer;
begin
base := Round(IntPower( 10, ndigits-1 ));
result := Trunc( value / BASE ) mod 10;
end;
nDigits is the digits number from right to left starting at 1. It will return the value of the digit.
GetDigits( 234, 1) returns 4
GetDigits( 234, 2) returns 3
GetDigits( 234, 3) returns 2.
GetDigits( 234, 4) returns 0.
Now this last function checks if a value is a good combination, specifying the maxdigits you're looking for :
function isValidCombination( value : integer; MinVal, MaxVal : Integer; MaxDigits : Integer ) : Boolean;
var
Buff : Array[0..9] of Integer;
nI, digit: Integer;
begin
ZeroMemory( #Buff, 10*4);
// Store the count of digits for
for nI := 1 to MaxDigits do
begin
digit := getDigits(value, nI);
Buff[digit] := Buff[digit] + 1;
end;
// Check if the value is more than the number of digits.
if Value >= Round(IntPower( 10, MaxDigits )) then
begin
result := False;
exit;
end;
// Check if the value has less than MaxDigits.
if Value < Round(IntPower( 10, MaxDigits-1 )) then
begin
result := False;
exit;
end;
result := true;
for nI := 0 to 9 do
begin
// Exit if more than One occurence of digit.
result := Buff[nI] < 2 ;
if not result then break;
// Check if digit is present and valid.
result := (Buff[nI] = 0) or InRange( nI, MinVal, MaxVal );
if not result then break;
end;
end;
Question does not seem too vague to me,
Maybe a bit poorly stated.
From what I understand you want to check if a string is in a set of randomly generated characters.
Here is how that would work fastest, keep a sorted array of all letters and how many times you have each letter.
Subtract each letter from the target string
If any value in the sorted int array goes under 0 then that means the string can not be made from those characters.
I made it just work with case insensitive strings but it can easily be made to work with any string by making the alphabet array 255 characters long and not starting from A.
This will not allow you to use characters twice like the other example
so 'boom' is not in 'b' 'o' 'm'
Hope this helps you.
function TForm1.isWordInArray(word: string; arr: array of Char):Boolean;
var
alphabetCount: array[0..25] of Integer;
i, baseval, position : Integer;
s: String;
c: Char;
begin
for i := 0 to 25 do alphabetCount[i] := 0; // init alphabet
s := UpperCase(word); // make string uppercase
baseval := Ord('A'); // count A as the 0th letter
for i := 0 to Length(arr)-1 do begin // disect array and build alhabet
c := UpCase(arr[i]); // get current letter
inc(alphabetCount[(Ord(c)-baseval)]); // add 1 to the letter count for that letter
end;
for i := 1 to Length(s) do begin // disect string
c := s[i]; // get current letter
position := (Ord(c)-baseval);
if(alphabetCount[position]>0) then // if there is still latters of that kind left
dec(alphabetCount[position]) // delete 1 to the letter count for that letter
else begin // letternot there!, exit with a negative result
Result := False;
Exit;
end;
end;
Result := True; // all tests where passed, the string is in the array
end;
implemented like so:
if isWordInArray('Delphi',['d','l','e','P','i','h']) then Caption := 'Yup' else Caption := 'Nope'; //yup
if isWordInArray('boom',['b','o','m']) then Caption := 'Yup' else Caption := 'Nope'; //nope, a char can only be used once
Delphi rocks!
begin
Randomize; //only need to execute this once.
sTmp := '';
While (Length(sTmp) < 3) Do
Begin
cTmp := IntToStr(Random(7) + 1)[1]; // RANDOM(7) produces # from 0..6
// so result will be '1'..'7', not '8'
// Alternative: clmp := chr(48 + random(8));
If (Pos(cTmp, sTmp) = 0) Then
sTmp := sTmp + cTmp;
IF SLMP = '324' THEN
DOSOMETHING; // don't know what you actually want to do
// Perhaps SET SLMP=''; to make sure '324'
// isn't generated?
end;
edt1.Text := sTmp;
end;

Converting 20-digit decimal value to Hexadecimal using delphi code

I am trying to convert 20 digit decimal value to hexadecimal using Delphi code. Although I find the code below in C#.
BigInteger bi = new BigInteger("12345678901234567890");
string s = bi.ToHexString();
Can anyone help with equivalent delphi code to achieve this objective?
Please note that using kstools code, I was able to convert 17 digit hexadecimal value to 20 digit decimal but I cannot reverse it to get back the hexadecimal value.
The kstool code is as follows:
var
I: TksInteger;
....
I.FromString('$ABDCF123456789FE');
Result = I.AsString;
Here's a Delphi translation of a C# answer to an identical question:
program DecToHex;
{$APPTYPE CONSOLE}
uses
SysUtils, Generics.Collections;
function DecimalToHex(const Dec: string): string;
var
bytes: Generics.Collections.TList<Byte>;
i, digit, val: Integer;
b: Byte;
c: Char;
begin
bytes := Generics.Collections.TList<Byte>.Create;
try
bytes.Add(0);
for c in Dec do
begin
Assert(CharInSet(c, ['0'..'9']));
val := ord(c)-ord('0');
for i := 0 to bytes.Count-1 do
begin
digit := bytes[i]*10 + val;
bytes[i] := digit and $0F;
val := digit shr 4;
end;
if (val<>0) then
bytes.Add(val);
end;
Result := '';
for b in bytes do
Result := '0123456789ABCDEF'[b+1] + Result;
finally
bytes.Free;
end;
end;
const
test = '56493153725735501823';
begin
WriteLn(test + ' = $' + DecimalToHex(test));
end.
Output:
56493153725735501823 = $30FFFFFFFFFFFFFFF
What's the problem exactly?
Using the example that you've given, it just works here.
Proof
This code converts 12345678901234567890 to a string, and then back to a number.
program Project122; {$APPTYPE CONSOLE}
uses SysUtils;
const SomeBigNumber=12345678901234567890;
var S:String; SomeBigNumber2:UInt64;
begin
WriteLn(SomeBigNumber);
S := '$'+IntToHex(SomeBigNumber, 40);
Writeln('As Hex: ',S);
Writeln;
Writeln('Now let''s convert it back...');
SomeBigNumber2 := StrToInt64(S);
Writeln(SomeBigNumber2);
ReadLn;
end.
output:
12345678901234567890 As Hex:
$AB54A98CEB1F0AD2
Now let's convert it back...
12345678901234567890
If you want to convert any 20-digit number, this won't work, because the largest ones don't fit in a UINT64.
18446744073709551615 is the largest number that you can fit in a UIN64.
12345678901234567890
The same as David Heffernan translation but optimized and compatible with older Delphi versions...
function DecimalToHex(const Dec: AnsiString): AnsiString;
var
ResultArray: array of byte;
n, i: Integer;
val, digit: Byte;
c: AnsiChar;
begin
SetLength(ResultArray, Trunc(Length(Dec) * Ln(10) / Ln(16)) + 1);
n := 0;
for c in Dec do
begin
Assert(CharInSet(c, ['0'..'9']));
val := ord(c) - ord('0');
for i := 0 to n do
begin
digit := ResultArray[i] * 10 + val;
ResultArray[i] := digit and $0F;
val := digit shr 4;
end;
if val <> 0 then
begin
inc(n);
ResultArray[n] := val;
end;
end;
Result := '';
for digit in ResultArray do
Result := AnsiString('0123456789ABCDEF')[digit + 1] + Result;
end;
The following Delphi function converts a decimal number and returns a right-justified hexadecimal number. It is not elegant, but it works.
//Uses STRUTILS Delphi module
function IHEX(x:Double): string; //Returns hex number as right-justified string
var i,k,a,mx:Integer;
y,Z,a1:currency;
s:string;
hxs: array[0..15] of string;
const hx='0123456789ABCDEF';
begin
Y:=abs(X); //Make sure target decimal is not a negative number
mx:=0; //Count number of hex digits derived from conversion
repeat
z:= y / 16; // Divide the decimal number by base 16
a:=Trunc(z); // Get integer part of dividend
if z>=16 then begin //If integer dividend greater than 16
a1:=16 * Frac(z);//Get the dividend carry-over
k:=Trunc(a1); // Base 16 left-to-right placement digit
If k<=9 then hxs[mx]:=IntToStr(k) //if hex digit greater than 9,
else
hxs[mx]:=hx[k+1]; //get hex alpha digit
mx:=mx+1; //increment hex digit placement
y:=a; //Replace decimal with current dividend result
end;
if z<16 then begin //When dividend less than 16,
a1:=16 * Frac(z); //get dividend carry-over
k:=Trunc(a1); //Base 16 left-to-right placement digit
If k<=9 then hxs[mx]:=IntToStr(k) //If hex digit greater than 9,
else
hxs[mx]:=hx[k+1]; //get hex alpha digit
mx:=mx+1; //increment hex digit placement
y:=a; //Replace decimal with current dividend result
end;
until y<16; //When loop ends, last hex digit derived from division
If a<=9 then hxs[mx]:=IntToStr(a) //If last hex digit greater than 9,
else
hxs[mx]:=hx[a+1]; //get hex alpha digit
//Pull HEX digits from placement array in reverse order to create HEX number
s:='';
i:=mx;
repeat
s:=s + hxs[i];
i:=i-1;
until i<0;
s:=s+'H';
//Format HEX number as seven characters RIGHT-JUSTIFIED
repeat
k:=Length(s);
if k<7 then s:='0'+s;
until Length(s)>=7;
Result:=s;
end;

How to keep 2 decimal places in Delphi?

I have selected columns from a database table and want this data with two decimal places only. I have:
SQL.Strings = ('select '#9'my_index '#9'his_index,'...
What is that #9?
How can I deal with the data I selected to make it only keep two decimal places?
I am very new to Delphi.
#9 is the character with code 9, TAB.
If you want to convert a floating point value to a string with 2 decimal places you use one of the formatting functions, e.g. Format():
var
d: Double;
s: string;
...
d := Sqrt(2.0);
s := Format('%.2f', [d]);
function Round2(aValue:double):double;
begin
Round2:=Round(aValue*100)/100;
end;
#9 is the tab character.
If f is a floating-point variable, you can do FormatFloat('#.##', f) to obtain a string representation of f with no more than 2 decimals.
For N Places behind the seperator use
function round_n(f:double; n:nativeint):double;
var i,m : nativeint;
begin
m := 10;
for i := 1 to pred(n) do
m := m * 10;
f := f * m;
f := round(f);
result := f / m;
end;
For Float to Float (with 2 decimal places, say) rounding check this from documentation. Gives sufficient examples too. It uses banker's rounding.
x := RoundTo(1.235, -2); //gives 1.24
Note that there is a difference between simply truncating to two decimal places (like in Format()), rounding to integer, and rounding to float.
Nowadays the SysUtils unit contains the solution:
System.SysUtils.FloatToStrF( singleValue, 7, ffFixed, 2 );
System.SysUtils.FloatToStrF( doubleValue, 15, ffFixed, 2 );
You can pass +1 TFormatSettings parameter if the requiered decimal/thousand separator differ from the current system locale settings.
The internal float format routines only work with simple numbers > 1
You need to do something more complicated for a general purpose decimal place limiter that works correctly on both fixed point and values < 1 with scientific notation.
I use this routine
function TForm1.Flt2str(Avalue:double; ADigits:integer):string;
var v:double; p:integer; e:string;
begin
if abs(Avalue)<1 then
begin
result:=floatTostr(Avalue);
p:=pos('E',result);
if p>0 then
begin
e:=copy(result,p,length(result));
setlength(result,p-1);
v:=RoundTo(StrToFloat(result),-Adigits);
result:=FloatToStr(v)+e;
end else
result:=FloatToStr(RoundTo(Avalue,-Adigits));
end
else
result:=FloatToStr(RoundTo(Avalue,-Adigits));
end;
So, with digits=2, 1.2349 rounds to 1.23 and 1.2349E-17 rounds to 1.23E-17
This worked for me :
Function RoundingUserDefineDecaimalPart(FloatNum: Double; NoOfDecPart: integer): Double;
Var
ls_FloatNumber: String;
Begin
ls_FloatNumber := FloatToStr(FloatNum);
IF Pos('.', ls_FloatNumber) > 0 Then
Result := StrToFloat
(copy(ls_FloatNumber, 1, Pos('.', ls_FloatNumber) - 1) + '.' + copy
(ls_FloatNumber, Pos('.', ls_FloatNumber) + 1, NoOfDecPart))
Else
Result := FloatNum;
End;
Function RealFormat(FloatNum: Double): string;
Var
ls_FloatNumber: String;
Begin
ls_FloatNumber:=StringReplace(FloatToStr(FloatNum),',','.',[rfReplaceAll]);
IF Pos('.', ls_FloatNumber) > 0 Then
Result :=
(copy(ls_FloatNumber, 1, Pos('.', ls_FloatNumber) - 1) + '.' + copy
(ls_FloatNumber, Pos('.', ls_FloatNumber) + 1, 2))
Else
Result := FloatToStr(FloatNum);
End;

Resources