3

I need to test if a double is an integer or not. Basically this is an example of the rule:

  • 5.0 > true
  • 5.2 > false

In order to do this I'd make an if (result mod 1) = 0 then and see the if it returns true or false. Consider that result is a double. By the way the compiler gives me this error:

[dcc32 Error] Unit1.pas(121): E2015 Operator not applicable to this operand type

How can I solve this problem? Note that my numbers are in this format ##.##### so I haven't many problems with the floating point precision.

In general I'd use if (result % 1 == 0) {} but in Delphi this does not work.

Kromster
  • 7,181
  • 7
  • 63
  • 111
Raffaele Rossi
  • 2,997
  • 4
  • 31
  • 62
  • You can check if the fraction is close to zero. "math" has "IsZero" which you can provide an epsilon. – Sertac Akyuz Jan 07 '17 at 00:36
  • An exact integer, or close enough? If only an exact integer, keep in mind that simple things such as `0.2 + 0.2 + 0.2 + 0.2 + 0.2` don't necessarily evaluate to an exact integer. If close enough, how close? –  Jan 07 '17 at 00:38
  • @SertacAkyuz You could do that, but the same percentages in rounding errors that turn 1 into 1.0000001 turn 1000000 into 1000000.1. Only looking at the fractional part without taking the magnitude into account is probably not a good idea. –  Jan 07 '17 at 00:39
  • @hvd - You can provide different epsilons according to magnitude if it is differing too much. – Sertac Akyuz Jan 07 '17 at 00:42
  • Check this simple solution, hope it help someone : https://stackoverflow.com/a/62449962/8545027 – Mostafa Amer Jun 18 '20 at 12:37

4 Answers4

9

You can use the function frac declared in the System unit of Delphi. Try with this code:

if ( frac(result) = 0 ) then
 ShowMessage('is zero')
else
 ShowMessage('is NOT zero');
end;

Check the documentation for details about the function. What you are doing is wrong because in Delphi the keyword mod only works with Integers.


Note. I have tested this with numbers such as 45.1234 and the code is correct. I see that you have a little number of digits in your double so there shouldn't be problems. I am not sure how accurate that function is, but in this case you don't have to worry.

Alberto Miola
  • 4,643
  • 8
  • 35
  • 49
  • Be wary of using `Frac()` as _Delphi_ does have some issues with floats. Given a variable `V: Double` with the value **15.2**, `Frac(V)` returns **0.199999999999999**. This was using _Delphi 10.2_. – SiBrit Apr 21 '20 at 00:47
0

That comparison would work in Freepascal....

{$mode objfpc}{$R+}
uses math;
var
  a:double =  5.2;
  b:double =  5.0;
begin
  writeln(a mod 1 = 0);
writeln(b mod 1 = 0);
end.

But it won't work in Delphi, I know...

In Delphi it should be with fmod:

uses math;
var
  a:double =  5.2;
  b:double =  5.0;
begin
  writeln(fmod(a,1) = 0);
  writeln(fmod(b,1) = 0);
end.
ivcubr
  • 1,988
  • 9
  • 20
  • 28
0

A Variation on @Alberto's answer. Just refined slightly to allow one to choose how precise (or imprecise) you want to be:

// is the passed FP number effectively an "integer";
// i.e. when rounded to AToPlaces decimal places, does it have only zero after dec point?
// AToPlaces -ve => after the dec point; same convention as for RoundTo; range -20 .. +20
  
function IsInteger(AFloat: Extended; AToPlaces: TRoundToEXRangeExtended = -3): boolean;
begin
  // Careful, this didn't work until I switched the order of Frac and RoundTo
  result := RoundTo(frac(AFloat), AToPlaces) = 0;
end;
TomB
  • 750
  • 4
  • 17
-1

maybe you want also to take care about the float imprecision, in this way you can do something like this :

if comparevalue(aValue, round(aValue), Tepsilon.vector) = 0 then 
  hasnodecimal 
else 
  hasdecimal
zeus
  • 12,173
  • 9
  • 63
  • 184
  • If you'd inspect source code of `comparevalue` you could simplify the code down to `Abs(aValue - Round(aValue)) < Tepsilon.vector` and then almost down to Alberto Miola answer of `frac(aValue) < Tepsilon.vector`. – Kromster Jan 18 '19 at 11:40