How can I make a single constant based on a hex value where that hex value is an unsigned integer and the raw memory for the single. I would like to do something like this but it doesn't compile and this will try and cast the hex value to a single and then store the result of that cast instead of storing hex value itself:
LARGEST_SINGLE_LESS_THAN_ZERO = Single($80800000);
I get a "Invalid Typecast" error.
For example:
The single value for 1 is stored as $3F800000 in memory. I would like to be able to create a const that lets me set the value using $3F800000 instead of 1.
I have also tried other variations such as this without luck:
LARGEST_SINGLE_LESS_THAN_ZERO = PSingle(#$80800000)^;
Background
I have a method that I use to get the next smallest single when provided with a single value:
type
PInt32 = ^Int32;
function NextBefore(const aValue: Single): Single;
var
int32Value: Int32;
begin
// this function ignores special values nan/inf
int32Value := PInt32(#aValue)^;
if (UInt32(int32Value) = $80000000) or (int32Value = 0) then
begin
// special handling needed for -0 and 0. We need to go to the smallest
// negative number.
int32Value := $80800000;
end
else
begin
if int32Value >= 0 then
Dec(int32Value)
else
Inc(int32Value);
end;
Result := PSingle(#int32Value)^;
end;
This is really useful because we use vector operations that can only do a > or < so we use it to do the equivalent of a >= and a <=. We often check against 0. So where we need get all of the data >= 0 we do something like this:
MyVector.ThresholdGT(NextBefore(0));
It would be nicer to provide the other developers with a constant for these types of operations. Trying to use the PSingle format below won't work because the number is not a variable.
In order to declare a single constant with a hex value in such a way that it cannot be altered by code, it can be done in two steps:
const
iLARGEST_SINGLE_LESS_THAN_ZERO : Int32 = $80800000;
var
LARGEST_SINGLE_LESS_THAN_ZERO : Single absolute iLARGEST_SINGLE_LESS_THAN_ZERO;
Trying to change the value of LARGEST_SINGLE_LESS_THAN_ZERO will give a compiler error: Left side cannot be assigned to.
It's hard to do this cleanly with the constraints of the language. Perhaps the best that you can do is to make a variant record type that has both integer and single fields overlapped.
type
TSingleIntegerVariantRec = record
case Integer of
0: (I: Integer);
1: (S: Single);
end;
Once you have that type available you can declare typed constants using the integer field, but then read the single field.
const
LARGEST_SINGLE_LESS_THAN_ZERO: TSingleIntegerVariantRec = (I: $80800000);
....
MyVector.ThresholdGT(LARGEST_SINGLE_LESS_THAN_ZERO.S);
If you want to add an extra nuance you could implement an implicit cast operator to Single which would allow you to omit the .S. If you made that operator inline then I suspect the emitted code would be very efficient.
This does what you ask, but I wouldn't claim that it was very elegant. We're I you I would move the code to use the next value down into the library function so that you can pass 0 and shield the consumer of the library from these implementation details.
In other words you would add a ThresholdGTequal method that was implemented like this:
procedure TMyVector.ThresholdGTequal(const Value: Single);
begin
ThresholdGT(NextBefore(Value));
end;
Then the consumers of this code simply write:
MyVector.ThresholdGTequal(0);
and remain oblivious to all of the gnarly implementation details.
Related
In Delphi, I declared a 3x3 matrix table as an array of array of Single, like this:
m_Table: array [0..2] of array [0..2] of Single;
Now I want to memory compare the content with another table, or memory copy the table content from another table. I know that I can create a nested loop to do that, but I want to do the job without any loop, if possible.
My question is, it is correct to copy or compare the memory like this:
CompareMem(m_Table, other.m_Table, 9 * SizeOf(Single));
CopyMemory(m_Table, other.m_Table, 9 * SizeOf(Single));
If not, what is the correct way to do that?
And as a subsidiary question, is there a better way to get the length to copy instead of 9 * SizeOf(Single), like e.g. SizeOf(m_Table^)?
Regards
The code in the question works fine. Personally I would say that Move is the idiomatic way to copy memory. Further I would use SizeOf(m_Table) to obtain the size of the type.
I would point out that your comparison differs from the floating point equality operator. Perhaps that's what you want, but you should be aware of this. For instance zero and minus zero compare equal using floating point comparison but not with memory compare. And NaNs always compare not equal, even with identical bit patterns.
Let me also comment that it would make your code more extendible if you declared a type for these matrices. Without that you won't be able to write functions that accept such objects.
The correct and easiest way may be to define a type:
type
TMatrix3x3 = array [0..2,0..2] of Single;
Then you can directly write:
var
v1, v2: TMatrix3x3;
begin
fillchar(v1,sizeof(v1),0);
move(v1,v2,sizeof(v1));
if comparemem(#v1,#v2,sizeof(v1)) then
writeln('equals');
end;
Using sizeof() make your code safe and readable.
You may define a wrapper type with methods:
{ TMatrix3x3 }
type
TMatrix3x3 = record
v: array [0..2,0..2] of Single;
procedure Zero;
procedure Copy(var dest: TMatrix3x3);
procedure Fill(const source: TMatrix3x3);
function Equals(const other: TMatrix3x3): boolean;
end;
procedure TMatrix3x3.Copy(var dest: TMatrix3x3);
begin
move(v,dest,sizeof(v));
end;
function TMatrix3x3.Equals(const other: TMatrix3x3): boolean;
begin
result := CompareMem(#v,#other.v,sizeof(v));
end;
procedure TMatrix3x3.Fill(const source: TMatrix3x3);
begin
move(source,v,sizeof(v));
end;
procedure TMatrix3x3.Zero;
begin
fillchar(v,sizeof(v),0);
end;
Including then advanced features like implicit assignment, and operators, if needed.
But don't reinvent the wheel, if you really to work with matrix arithmetic. Use an already existing and fully tested library, which will save you a lot of trouble and debugging time.
You should use standard TMatrix type from System.Math.Vectors unit, then you can just compare it directly as if Matrix1 = Matrix2 then and assign as Matrix1 := Matrix2
Write a program to convert an integer number to its hexadecimal representation without using inbuilt functions.
Here is my code, but it is not working. Can anyone tell where is the mistake?
It is giving an error:
"Project raised exception class EAccessViolation with message 'Access violation at address 00453B7B in module 'Project.exe'.Write of address FFFFFFFF'.Process stopped.Use Step or Run to continue."
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,Forms,
Dialogs;
type
TForm1 = class(TForm)
end;
function hexvalue(num:Integer):Char;
var
Form1: TForm1;
implementation
{$R *.dfm}
function hexvalue(num:Integer):Char;
begin
case num of
10: Result:='A';
11: Result:='B';
12: Result:='C';
13: Result:='D';
14: Result:='E';
15: Result:='F';
else Result:=Chr(num);
end;
end;
var
intnumber,hexnumber,actualhex:String;
integernum:Integer;
i,j,k:Byte;
begin
InputQuery ('Integer Number','Enter the integer number', intnumber);
integernum:=StrToInt(intnumber);
i:=0;
while integernum >= 16 do
begin
hexnumber[i]:=hexvalue(integernum mod 16);
integernum:= integernum div 16;
Inc(i);
end;
hexnumber[i]:= hexvalue(integernum);
k:=i;
for j:=0 to k do
begin
actualhex[j]:= hexnumber[i];
Dec(i);
end;
ShowMessage(actualhex);
end.
Since this obviously is a homework assignment, I don't want to spoil it for you and write the solution, but rather attempt to guide you to the solution.
User input
In real code you would need to be prepared for any mistake from the user and check that the input really is integer numbers only and politely ask the user to correct the input if erroneous.
Conversion loop
You have got that OK, using mod 16 for each nibble of integernum and div 16 to move to the next nibble, going from units towards higher order values.
Conversion of nibble to hex character
Here you go wrong. If you would have written out also the cases for 0..9, you could have got the case statement right. As others have commented, Chr() takes an ASCII code. However, using a case statement for such a simple conversion is tedious to write and not very efficient.
What if you would have a lookup table (array) where the index (0..15) directly would give you the corresponding hex character. That would be much simpler. Something like
const
HexChars: array[_.._] of Char = ('0',_____'F')
I leave it to you to fill in the missing parts.
Forming the result (hex string)
Your second major mistake and the reason for the AV is that you did not set the length of the string hexnumber before attempting to acess the character positions. Another design flaw is that you fill in hexnumber backwards. As a result you then need an extra loop where you reverse the order to the correct one.
There are at least two solutions to solve both problems:
Since you take 32 bit integer type input, the hex representation is not more than 8 characters. Thus you can preset the length of the string to 8 and fill it in from the lower order position using 8 - i as index. As a final step you can trim the string if you like.
Don't preset the length and just concatenate as you go in the loop hexnumber := HexChars[integernum mod 16] + hexnumber;.
Negative values
You did not in any way consider the possibility of negative values in your code, so I assume it wasn't part of the task.
First mistake : String are 1 indexed. Meaning that the index of their first character is 1 and not 0. You initialize "i" to 0 and then try to set hexnumber[i].
Second mistake : Strings might be dynamic, but they don't grow automatically. If you try to access the first character of an empty string, it won't work. You need to call SetLength(HeXNumber, NumberOfDigits). You can calculate the number of digits this way :
NumberOfDigits := Trunc(Log16(integernum)) + 1;
Since Log16 isn't really something that exists, you can either use LogN(16,integernum) or (Log(IntegerNum) / Log(16)) depending on what is available in your version of Delphi.
Note that this might return an invalid value for very, very large value (high INT64 range) due to rounding errors.
If you don't want to go that road, you could replace the instruction by
hexnumber := hexvalue(integernum mod 16) + hexnumber;
which would also remove the need to invert the string at the end.
Third Mistake : Using unsigned integer for loop variable. While this is debatable, the instruction
for I := 0 to Count - 1 do
is common practice in Delphi without checking Count > 0. When count = 0 and using an unsigned loop counter, you'll either get an integer overflow (if you have them activated in your project options) or you'll loop High(I) times, which isn't what you want to be doing.
Fourth mistake : already mentionned : Result:=Chr(num) should be replaced by something like Result := InttoStr(Num)[1].
Personally, I'd implement the function using an array.
HexArr : Array[0..15] of char = ('0', '1',...,'D','E','F');
begin
if InRange(Num, 0, 15) then
Result := HexArr[Num]
else
//whatever you want
end;
I'm working on a vintage code base and I am very new to delphi, so apologies in advance if my syntax is off a bit (or just plain wrong).
I have things like a pre defined (at compile time) array. arr and we used all over the place
file1.pas: arr[1] := 3.14
file2.pas: pi := arr[1]
And I've noticed that we never,ever use constants to access elements in the array. In C I would write:
int arr[100] = {0};
const int MY_INDEX=1;
arr[MY_INDEX] = 3.14
etc. But I don't see that in my delphi code base. Is that because Delphi/Pascal doesn't support it or because the original authors decided not to do it?
Thanks
Delphi allows you to use a constant as an array index. So if you don't see such a thing in your code, it's because the authors elected not to declare and use constants for array indices.
Yes constants can be used along with any expression that evaluates to an appropriate and valid index for the array. You should also note that an array in Delphi could be declared with a non-zero based index range:
var
MonthlyTotals: array[1..12] of Integer; // Jan = 1, Feb = 2 etc etc
You can even specify the index of an array as an enum type and use enum members for the indices which provides even tighter safety (where possible and appropriate), as per this contrived example:
type
TFileFormat = (ffXML, ffCSV, ffText, ffJSON);
var
sExtensions: array[TFileFormat] of String;
sExtensions[ffXML] := 'xml';
sExtensions[ffCSV] := 'csv';
sExtensions[ffText] := 'txt';
sExtensions[ffJSON] := 'json';
In such cases the array might only have members for certain (contiguous) values in the enum:
var
sExtensions: array[ffXML..ffCSV] of String;
For this reason, and the fact that array indices may not be zero based, unless you are 110% certain of the index range of an array it is a good idea to always use Low() and High() to determine the index bounds when iterating over the contents of an array and not assume the index basis:
// This will not work properly:
for i := 0 to 11 do
MonthlyTotals[i] := ....
// Neither will this, even though it looks more safe
for i := 0 to Pred(Length(MonthlyTotals)) do
MonthlyTotals[i] := ....
// This will be safe:
for i := Low(MonthlyTotals) to High(MonthlyTotals) do
MonthlyTotals[i] := ....
// And it works for enum indices as well:
for ext := Low(sExtensions) to High(sExtensions) do
sExtensions[ext] := ....
The exact conversion of your C code in Delphi would be along the lines of:
var
arr: array[100] of integer;
const
MY_INDEX = 1;
begin
arr[MY_INDEX] := 3.14;
end;
As others have said, perfectly feasible and the enum method is arguably a better alternative. One gotcha here is that this is relying on Delphi having the array initialised zeroed rather than setting it explicitly as in C.
I am trying to build a function/check to prevent wrong inputs from keyboard and I am a little bit lost here.
function ReadInputs : integer;
var
number : integer;
begin
repeat
Write('Set random number (1-10): ');
Readln(number);
if NOT((number <= 10) AND (number >= 1)) then
begin
Writeln('Error! Type 1-10!');
end;
until (number >= 1) AND (number <= 10);
result := column;
end;
How to prevent from any other character to be input except numbers 1-10? Why only numbers define in my function is not enough even when I set integer? When I type for example "A" it crash, so what is the right way? Thank you.
As it stands your program will fail with an error if the user inputs something that cannot be converted to an integer. That's because the variable that you passed to Readln is typed as an Integer. That is effectively an assertion that the user enters a number. But you want to be more flexible than that and allow the user to recover from non-numeric input.
What you need to do is read a string. This will always succeed. Then you can decide how to handle that string. For example you would try to convert to integer, and if that succeeded, perform further validity checks.
Perhaps like this:
var
Input: string;
Num: Integer;
....
Readln(Input);
if TryStrToInt(Input, Num) then
// perform checks on Num, etc.
else
// handle error: the value input was not numeric
You've already had a good answerfrom David H, but a little more explanation might help.
The ReadLn() procedure dates from before applications had GUIs and doesn't really restrict what the user can type in; the user might just press [return] or type characters that aren't digits (or +/-). ReadLn(AnInteger) will succeed if what the user types happens to convert to an integer, otherwise it fails.
On the other hand, Readln(AString) will always succeed, and the problem then is just how to check that it represents an integer, and DH's answer shows you how to do that.
In case you're wondering, a GUI application, you can control what characters an edit control will accept, e.g. by using a TMaskEDit, which allows you specify what character patterns are acceptable (e.g 6 digits and nothing else) - if the user types something which doesn't match the mask, the edit control doesn't accept it. However, even if you use a TMaskEdit, it's best to check that what's been typed in actually converts to the number type you're wanting.
Or you could use this on the OnKeyPress event:
if NOT(key in['0'..'9', #8]) then
key := #0;
Consider the following record:
TMyRecord = record
b: Boolean;
// 3 bytes of padding in here with default record alignment settings
i: Integer;
end;
I wish to implement IEqualityComparer<TMyRecord>. In order to do so I want to call TEqualityComparer<TMyRecord>.Construct. This needs to be supplied with a TEqualityComparison<TMyRecord> which presents no problems to me.
However, Construct also requires a THasher<TMyRecord> and I would like to know the canonical method for implementing that. The function needs to have the following form:
function MyRecordHasher(const Value: TMyRecord): Integer;
begin
Result := ???
end;
I expect that I need to call BobJenkinsHash on both fields of the record value and then combine them some how. Is this the right approach, and how should I combine them?
The reason I don't use TEqualityComparison<TMyRecord>.Default is that it uses CompareMem and so will be incorrect due to the record's padding.
The Effective Java (by Joshua Bloch) section about overriding hashCode could be useful. It shows how the individual parts of the object (or record) can be combined to efficiently construct a hashCode.
A good hash function tends to produce unequal hash codes for unequal
objects. This is exactly what is meant by the third provision of the
hashCode contract. Ideally, a hash function should distribute any
reasonable collection of unequal instances uniformly across all
possible hash values. Achieving this ideal can be extremely difficult.
Luckily it is not too difficult to achieve a fair approximation. Here
is a simple recipe:
Store some constant nonzero value, say 17, in an int variable called result.
For each significant field f in your object (each field taken into account by the equals method, that is), do the following:
a. Compute an int hash code c for the field: ..... details omitted ....
b. Combine the hash code c computed in step a into
result as follows: result = 37*result + c;
Return result.
When you are done writing the hashCode method, ask yourself whether equal instances have equal hash codes. If not, figure out why
and fix the problem.
This can be translated into Delphi code as follows:
{$IFOPT Q+}
{$DEFINE OverflowChecksEnabled}
{$Q-}
{$ENDIF}
function CombinedHash(const Values: array of Integer): Integer;
var
Value: Integer;
begin
Result := 17;
for Value in Values do begin
Result := Result*37 + Value;
end;
end;
{$IFDEF OverflowChecksEnabled}
{$Q+}
{$ENDIF}
This then allows the implementation of MyRecordHasher:
function MyRecordHasher(const Value: TMyRecord): Integer;
begin
Result := CombinedHash([IfThen(Value.b, 0, 1), Value.i]);
end;