I'm trying to code something but there is happening something I don't understand.
I get some values from a database and loop over them and change some of them if needed.
This is what I'm trying to do:
if qryGeneral.fieldbyname('B_PRIJS').IsNull or
qryGeneral.fieldbyname('B_PRIJS').Value = 0 then
begin
if (qryGeneral.fieldbyname('V_PRIJS').Value <> 0) or
(qryGeneral.fieldbyname('V_PRIJSEXCL').Value <> 0) then
//make some calculations and save data
end;
B_PRIJS is a float, null type in a SQL Server DB. When I set a breakpoint and I hover .Value it shows 0,11. When I hover IsNull it shows False, so far so good.
Now I would expect it would NOT enter the if-structure, because it is not null and not equal to 0, but it does enter the if-structure.
I don't understand why, I always coded like this.
When I select qryGeneral.fieldbyname('B_PRIJS').Value = 0 while still being in debug mode, I get a message "Expression illegal in evaluator".
I tried replacing Value into AsFloat or changing 0 into 0.0 but it doesn't work.
What am I doing wrong or not understanding here?
Delphi's operator precedence rules mean that your expression is evaluated like this:
if (qryGeneral.fieldbyname('B_PRIJS').IsNull or qryGeneral.fieldbyname('B_PRIJS').Value)
= 0 then
Put parentheses around your = expression just like you have around you <> expressions, and you should get closer to the results you expect. However, the Value property is a Variant. When comparing a Variant to an Integer, the = operator will cause the Variant to be converted to an Integer. Delphi's variant-type-conversion rules show that a Variant holding a real value will be rounded to the nearest integer when the target type is an integer, so your 0.11 value will be rounded to zero. Consider comparing to 0.0 instead.
Related
I have a double value that I need to access to inside a backgroundThread. I would like to use somethink like AtomiccmpExchange but seam to not work with double. is their any other equivalent that I can use with double ? I would like to avoid to use Tmonitor.enter / Tmonitor.exit as I need something the most fast as possible. I m under android/ios so under firemonkey
You could type cast the double values into UInt64 values:
PUInt64(#dOld)^ := AtomicCmpExchange(PUInt64(#d)^,PUInt64(#dNew)^,PUInt64(#dComp)^);
Note that you need to align the variables properly, according to platforms specifications.
As #David pointed out, comparing doublevalues is not the same as comparing UInt64 values. There are some specific double values that will behave out of the ordinary:
A NaN is normally (as specified in IEEE-754) detected by comparing a value by itself.
IsNaN := d <> d;
footnote: Delphi default exception handler is triggered in the event of comparing a NaN, but other compilers may behave differently. In Delphi there is an IsNaN() function to use instead.
Likewise the value zero could be both positive and negative, for a special meaning. Comparing double 0 with double -0 will return true, but comparing the memory footprint will return false.
Maybe use of System.SyncObjs.TInterlocked class methods will be better?
In a loop like this:
cur := -999999; // represent a minimal possible value hold by a Single type
while ... do
begin
if some_value > cur then
cur := some_value;
end;
There is MaxSingle/NegInfinitydefined in System.Math
MaxSingle = 340282346638528859811704183484516925440.0;
NegInfinity = -1.0 / 0.0;
So should I use -MaxSingle or NegInfinity in this case?
I assume you are trying to find the largest value in a list.
If your values are in an array, just use the library function MaxValue(). (If you look at the implementation of MaxValue, you'll see that it takes the first value in the array as the starting point.)
If you must implement it yourself, use -MaxSingle as the starting value, which is approximately -3.40e38. This is the most negative value that can be represented in a Single.
Special values like Infinity and NaN have special rules in comparisons, so I would avoid these unless you are sure about what those rules are. (See also How do arbitrary floating point values compare to infinity?. In fact, it seems NegInfinity would work OK.)
It might help to understand the range of values that can be represented by a Single. In order, most negative to most positive, they are:
NegInfinity
-MaxSingle .. -MinSingle
0
MinSingle .. MaxSingle
Infinity
I have a record declared as
T3DVector = record
X,Y,Z: Integer;
end;
One variable V of type T3DVector holds:
V.X= -25052
V.Y= 34165
V.Z= 37730
I then try to the following line. D is declared as Double.
D:= (V.X*V.X) + (V.Y*V.Y) + (V.Z*V.Z);
The return value is: -1076564467 (0xFFFFFFFFBFD4EE0D)
The following code should be equivalent:
D:= (V.X*V.X);
D:= D + (V.Y*V.Y);
D:= D + (V.Z*V.Z);
But this,however, returns 3218402829 (0x00000000BFD4EE0D), which actually is the correct value.
By looking at the high bits, I thought this was an overflow problem. When I turned on overflow checking, the first line halted with the exception "Integer overflow". This is even more confusing to me because D is Double, and I am only storing values into D
Can anyone clarify please ?
The target of an assignment statement has no bearing on how the right side is evaluated. On the right side, all you have are of type Integer, so the expression is evaluated as that type.
If you want the right side evaluated as some other type, then at least one operand must have that type. You witnessed this when you broke the statement into multiple steps, incorporating D into the right side of the expression. The value of V.Y * V.Y is still evaluated as type Integer, but the result is promoted to have type Double so that it matches the type of the other operand in the addition term (D).
The fact that D is a double doesn't affect the type of X, Y and Z. Those are Integers, and are apparently not large enough to store the squares of such large numbers, and their multiplication is what overflows. Why don't you declare them as doubles, too?
I've come across some rather unusual behaviour in a bit of Delphi code. When using the in keyword to check if an item is in a constant array, I get the following compilation error:
E1012 Constant expression violates subrange bounds
The constants are defined as follows:
type TSomeEnum = (seFoo = 1000,
seBar = 2000,
seBoo = 3000,
seFar = 4000,
seFooBar = 5000,
seBooFar = 6000,
seLow = 1000,
seHigh = 6000,
seCount = 6);
The line that is failing is the following:
if someObj.someProperty in [seFoo, seFar, seFooBar] then
...
Whilst I understand the reasoning behind the error showing in another question posted here, where bounds checking on integer arrays wasn't done at compile time when using a variable, it seems odd that I'm getting the same problem with a constant array which is most certainly within bounds.
For now, I've replaced the line with a (much larger) statement comprising of or clauses. However, this is clearly not ideal. Can anyone shed any light on why I'm getting this problem?
Documentation about Sets says :
The base type can have no more than 256 possible values, and their ordinalities must fall between 0 and 255.
So even if you can have enums of any value, the if xx in [a,b,c] statement will fail here, since a set cannot hold a value larger than 255.
Use a case statement instead:
case xx of
a,b,c : // Make something
end;
When accessing an element in an array the square brackets are used like so:
{'X is an int and Numbers is an int array'}
X := Numbers[8];
However, While reading others' code I sometimes find the following syntax:
{'PBox , SBox1 , SBox2 are arrays of int , And X,Y are ints'}
Result := Result or PBox(.SBox1[X] or SBox2[Y].);
What does it mean to have parentheses after the array's name, as in PBox(someNumber)? Is this another way to access an array element?
What does the "." before SBox1 and after SBox2 mean? Both SBox1 and SBox2 are arrays. The code compiles without error but I don't know what those dots are for.
Yes, now I see what you do.
In fact, (. and .) are merely alternative ways (but very uncommon!) of writing [ and ] in Delphi.
If PBox is an array, then PBox[a] (or, equivalently, PBox(.a.)) would require a to be an integer, right? And if SBox1[x] and SBox2[Y] are integers, so is the bitwise or of them. (Bitwise or is an operation that takes two integers and returns a new integer.) Hence, PBox(.SBox1[X] or SBox2[Y].) is the (SBox1[X] or SBox2[Y])th element in the array PBox, that is, an integer. So it makes sense to compute the bitwise or between Result and this integer, which is what is done:
Result := Result or PBox(.SBox1[X] or SBox2[Y].);