How do I define a range of floats? - delphi

I want to define a percentage type.
TPrecent = 0 .. 100; works fine, but I can only assign integers to it an dwoudl also like to assign floats.
How can I do that?

Ranges can only be integer ordinal types. You will need to use a float variable and validate the value yourself.

TPercent is an integer sub-range. You cannot create a sub-range that is a floating point underlying type.

Related

how to use AtomiccmpExchange with double?

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(#dCom‌​p)^);
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?

single, double and precision

I know that storing single value (or double) can not be very precise. so storing for example 125.12 can result in 125.1200074788. now in delphi their is some usefull function like samevalue or comparevalue that take an epsilon as param and say that 125.1200074788 or for exemple 125.1200087952 is equal.
but i often see in code stuff like : if aSingleVar = 0 then ... and this in fact as i see always work. why ? why storing for exemple 0 in a single var keep the exact value ?
Only values that are in form m*2^e, where m and e are integers can be stored in a floating point variable (not all of them though, it depends on precision). 0 has this form, and 125.12 does not, as it equals 3128/25, and 1/25 is not an integer power of 2.
Comparing 125.12 to a single (or double) precision variable will most probably return always False, because a literal 125.12 will be treated as an extended precision number, and no single (or double) precision number would have such a value.
Looks like a good use for the BigDecimals unit by Rudy Velthuis. Millions of decimal places of accuracy and precision.

What is the correct constant to use when comparing with the Minimal Single Number in Delphi?

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

cannot be applied to operands of type 'UITextField' and 'Int'

I am trying to populate a Label with a text field input * 365
I keep getting the message:
Binary operator '*' cannot be applied to operands of type 'UITextField' and 'Int'
var hours = (hoursTextField.text as NSString).doubleValue
var hoursInAYear = hoursTextField * 365
Your first line is calculating the doubleValue of what's entered into the text field, but you're not using that hours variable. Perhaps you want:
var hoursInAYear = hours * 365
The warning you are getting is telling you that you're trying to use the * operator between a variable whose type is UITextField and another variable whose type is Int (this is what your 365 literal is interpreted as).
This warning will come up any time we try to use an operator between two types for which the operator does not have an overload. It is particularly common when one of our operand's types is implicitly determined because we're using a literal somewhere. To resolve the issue, we must double check our instantiation of our operands and be sure they're of types for which our operator has an overload.
If they are not, then we should either change how we create these variables so they have the right type, or find some way of converting them when we use them with the operator.
When we change our mistaken variable from the text field to the double we just calculated, Swift is able to calculate this correctly. Despite previously claiming that 365 was an Int, being a literal, it can be interpreted as several different types, one of which includes Double.
When we attempt to use the * between a variable of type Double and a literal number, the literal number will be correctly converted to a Double, and we'll use the overload of the * operator which accepts two doubles (and returns a double).
You're trying to multiply hoursTextField by 365. Did you mean to write:
var hours = (hoursTextField.text as NSString).doubleValue
var hoursInAYear = hours * 365 // hours, not hoursTextField.
I think it is basically just a typo or copy-paste-mistake of yours since you already calculate the hours variable correctly and dont use it afterwards. Simply change your second line to
var hoursInAYear = hours * 365

Objective C ceil returns wrong value

NSLog(#"CEIL %f",ceil(2/3));
should return 1. However, it shows:
CEIL 0.000000
Why and how to fix that problem? I use ceil([myNSArray count]/3) and it returns 0 when array count is 2.
The same rules as C apply: 2 and 3 are ints, so 2/3 is an integer divide. Integer division truncates so 2/3 produces the integer 0. That integer 0 will then be cast to a double precision float for the call to ceil, but ceil(0) is 0.
Changing the code to:
NSLog(#"CEIL %f",ceil(2.0/3.0));
Will display the result you're expecting. Adding the decimal point causes the constants to be recognised as double precision floating point numbers (and 2.0f is how you'd type a single precision floating point number).
Maudicus' solution works because (float)2/3 casts the integer 2 to a float and C's promotion rules mean that it'll promote the denominator to floating point in order to divide a floating point number by an integer, giving a floating point result.
So, your current statement ceil([myNSArray count]/3) should be changed to either:
([myNSArray count] + 2)/3 // no floating point involved
Or:
ceil((float)[myNSArray count]/3) // arguably more explicit
2/3 evaluates to 0 unless you cast it to a float.
So, you have to be careful with your values being turned to int's before you want.
float decValue = (float) 2/3;
NSLog(#"CEIL %f",ceil(decValue));
==>
CEIL 1.000000
For you array example
float decValue = (float) [myNSArray count]/3;
NSLog(#"CEIL %f",ceil(decValue));
It probably evaluates 2 and 3 as integers (as they are, obviously), evaluates the result (which is 0), and then converts it to float or double (which is also 0.00000). The easiest way to fix it is to type either 2.0f/3, 2/3.0f, or 2.0f/3.0f, (or without "f" if you wish, whatever you like more ;) ).
Hope it helps

Resources