Test integerness: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Elixir}}: Add Fortran.)
Line 113: Line 113:
:"123" is integer?: false
:"123" is integer?: false
</pre>
</pre>
=={{header|Fortran}}==
The issue is a little delicate, because a number such as 3E120 is integral, but, cannot be represented in an ordinary integer variable. If the idea slides towards whether the value can be represented exactly by an integer variable then the task become easy. The following code takes advantage of the availability of INTEGER*8 variables, and an associated function KIDINT(x) that deals with double precision values and returns a 64-bit integer result. This function truncates - if it were to round then it might want to round up to one beyond the maximum possible integer of that sign. There is a bewildering variety of these truncation and rounding functions, some of which are generic and some not, and if only INTEGER*4 were available, different choices would have to be made.

The MODULE protocol of F90 is used, merely to save on the need to define the types of the function in each routine that uses them. A lot more gibberish could be added to define an INTERFACE, etc. whereby these functions can present themselves as generic but lacking this, they must be invoked with the right type of parameter.
<lang Fortran>
MODULE ZERMELO !Approach the foundations of mathematics.
CONTAINS
LOGICAL FUNCTION ISINTEGRAL(X) !A whole number?
REAL*8 X !Alas, this is not really a REAL number.
INTEGER*8 N !Largest available.
IF (ISNAN(X)) THEN !Avoid some sillyness.
ISINTEGRAL = .FALSE. !And possible error messages.
ELSE !But now it is safe to try.
N = KIDINT(X) !This one truncates.
ISINTEGRAL = N .EQ. X !Any difference?
END IF !A floating-point number may overflow an integer.
END FUNCTION ISINTEGRAL !And even if integral, it will not seem so.

LOGICAL FUNCTION ISINTEGRALZ(Z) !For complex numbers, two tests.
DOUBLE COMPLEX Z !Still not really REAL, though.
ISINTEGRALZ = ISINTEGRAL(DBLE(Z)) .AND. ISINTEGRAL(DIMAG(Z)) !Separate the parts.
END FUNCTION ISINTEGRALZ!No INTEGER COMPLEX type is offered.
END MODULE ZERMELO !Much more mathematics lie elsewhere.

PROGRAM TEST
USE ZERMELO
DOUBLE COMPLEX Z

WRITE (6,*) "See if some numbers are integral..."
WRITE (6,*) "666",ISINTEGRAL(666D0)
Z = DCMPLX(-3D0,4*ATAN(1D0))
WRITE (6,*) Z,ISINTEGRALZ(Z)
END
</lang>
<pre>
See if some numbers are integral...
666 T
(-3.00000000000000,3.14159265358979) F
</pre>
If however large numbers are to be affirmed as integral even if there is no integer variable capable of holding such values, then a different approach is possible. F90 standardised the functions FRACTION(x) and EXPONENT(x) that reveal the parts of a floating point number. With the assistance of the RADIX(x) function that reports the base of the number system, the value could be inspected to see whether it contained any fractional part...


=={{header|Go}}==
=={{header|Go}}==

Revision as of 10:07, 25 March 2016

Test integerness is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given a numeric, possibly complex value, test whether or not it is an integer.

To be clear, we're not talking about whether the number is stored with the specific data type for integers, but instead we want to test whether there exists an integer with the exact same value. In other words, we want to test for integerness in the mathematical sense, not as a data type.

C

The main function that checks a numeric value is actually quite short. Because of C's weak types and implicit casting we can get away with making a function which checks long double complex types only.

<lang c>

  1. include <stdio.h>
  2. include <complex.h>
  3. include <math.h>

/* Testing macros */

  1. define FMTSPEC(arg) _Generic((arg), \
   float: "%f", double: "%f", \
   long double: "%Lf", unsigned int: "%u", \
   unsigned long: "%lu", unsigned long long: "%llu", \
   int: "%d", long: "%ld", long long: "%lld", \
   default: "(invalid type (%p)")
  1. define CMPPARTS(x, y) ((long double complex)((long double)(x) + \
           I * (long double)(y)))
  1. define TEST_CMPL(i, j)\
   printf(FMTSPEC(i), i), printf(" + "), printf(FMTSPEC(j), j), \
   printf("i = %s\n", (isint(CMPPARTS(i, j)) ? "true" : "false"))
  1. define TEST_REAL(i)\
   printf(FMTSPEC(i), i), printf(" = %s\n", (isint(i) ? "true" : "false"))

/* Main code */ static inline int isint(long double complex n) {

   return cimagl(n) == 0 && nearbyintl(creall(n)) == creall(n);

}

int main(void) {

   TEST_REAL(0);
   TEST_REAL(-0);
   TEST_REAL(-2);
   TEST_REAL(-2.00000000000001);
   TEST_REAL(5);
   TEST_REAL(7.3333333333333);
   TEST_REAL(3.141592653589);
   TEST_REAL(-9.223372036854776e18);
   TEST_REAL(5e-324);
   TEST_REAL(NAN);
   TEST_CMPL(6, 0);
   TEST_CMPL(0, 1);
   TEST_CMPL(0, 0);
   TEST_CMPL(3.4, 0);
   /* Demonstrating that we can use the same function for complex values
    * constructed in the standard way */
   double complex test1 = 5 + 0*I,
                  test2 = 3.4f,
                  test3 = 3,
                  test4 = 0 + 1.2*I;
   printf("Test 1 (5+i) = %s\n", isint(test1) ? "true" : "false");
   printf("Test 2 (3.4+0i) = %s\n", isint(test2) ? "true" : "false");
   printf("Test 3 (3+0i) = %s\n", isint(test3) ? "true" : "false");
   printf("Test 4 (0+1.2i) = %s\n", isint(test4) ? "true" : "false");

} </lang>

Output:

Note: Some of the printed results are truncated and look incorrect. See the actual code if you wish to verify the actual value.

0 = true
0 = true
-2 = true
-2.000000 = false
5 = true
7.333333 = false
3.141593 = false
-9223372036854775808.000000 = true
0.000000 = false
nan = false
6 + 0i = true
0 + 1i = false
0 + 0i = true
3.400000 + 0i = false
Test 1 (5+i) = true
Test 2 (3.4+0i) = false
Test 3 (3+0i) = true
Test 4 (0+1.2i) = false

Elixir

<lang elixir>defmodule Test do

 def integer?(n) when n == trunc(n), do: true
 def integer?(_), do: false

end

Enum.each([2, 2.0, 2.5, 2.000000000000001, 1.23e300, 1.0e-300, "123", '123', :"123"], fn n ->

 IO.puts "#{inspect n} is integer?: #{Test.integer?(n)}"

end)</lang>

Output:
2 is integer?: true
2.0 is integer?: true
2.5 is integer?: false
2.000000000000001 is integer?: false
1.23e300 is integer?: true
1.0e-300 is integer?: false
"123" is integer?: false
'123' is integer?: false
:"123" is integer?: false

Fortran

The issue is a little delicate, because a number such as 3E120 is integral, but, cannot be represented in an ordinary integer variable. If the idea slides towards whether the value can be represented exactly by an integer variable then the task become easy. The following code takes advantage of the availability of INTEGER*8 variables, and an associated function KIDINT(x) that deals with double precision values and returns a 64-bit integer result. This function truncates - if it were to round then it might want to round up to one beyond the maximum possible integer of that sign. There is a bewildering variety of these truncation and rounding functions, some of which are generic and some not, and if only INTEGER*4 were available, different choices would have to be made.

The MODULE protocol of F90 is used, merely to save on the need to define the types of the function in each routine that uses them. A lot more gibberish could be added to define an INTERFACE, etc. whereby these functions can present themselves as generic but lacking this, they must be invoked with the right type of parameter. <lang Fortran>

     MODULE ZERMELO	!Approach the foundations of mathematics.
      CONTAINS
       LOGICAL FUNCTION ISINTEGRAL(X)	!A whole number?
        REAL*8 X	!Alas, this is not really a REAL number.
        INTEGER*8 N	!Largest available.
         IF (ISNAN(X)) THEN	!Avoid some sillyness.
           ISINTEGRAL = .FALSE.	!And possible error messages.
         ELSE			!But now it is safe to try.
           N = KIDINT(X)		!This one truncates.
           ISINTEGRAL = N .EQ. X	!Any difference?
         END IF		!A floating-point number may overflow an integer.
       END FUNCTION ISINTEGRAL	!And even if integral, it will not seem so.
       LOGICAL FUNCTION ISINTEGRALZ(Z)	!For complex numbers, two tests.
        DOUBLE COMPLEX Z	!Still not really REAL, though.
         ISINTEGRALZ = ISINTEGRAL(DBLE(Z)) .AND. ISINTEGRAL(DIMAG(Z))	!Separate the parts.
       END FUNCTION ISINTEGRALZ!No INTEGER COMPLEX type is offered.
     END MODULE ZERMELO	!Much more mathematics lie elsewhere.
     PROGRAM TEST
     USE ZERMELO
     DOUBLE COMPLEX Z
     WRITE (6,*) "See if some numbers are integral..."
     WRITE (6,*) "666",ISINTEGRAL(666D0)
     Z = DCMPLX(-3D0,4*ATAN(1D0))
     WRITE (6,*) Z,ISINTEGRALZ(Z)
     END

</lang>

 See if some numbers are integral...
 666 T
 (-3.00000000000000,3.14159265358979) F

If however large numbers are to be affirmed as integral even if there is no integer variable capable of holding such values, then a different approach is possible. F90 standardised the functions FRACTION(x) and EXPONENT(x) that reveal the parts of a floating point number. With the assistance of the RADIX(x) function that reports the base of the number system, the value could be inspected to see whether it contained any fractional part...

Go

<lang go>package main

import ( "fmt" "math" "math/big" "reflect" "strings" "unsafe" )

// Go provides an integerness test only for the big.Rat type in the standard // library.

// The fundamental piece of code needed for built-in floating point types // is a test on the float64 type:

func Float64IsInt(f float64) bool { _, frac := math.Modf(f) return frac == 0 }

// Other built-in or stanadard library numeric types are either always // integer or can be easily tested using Float64IsInt.

func Float32IsInt(f float32) bool { return Float64IsInt(float64(f)) }

func Complex128IsInt(c complex128) bool { return imag(c) == 0 && Float64IsInt(real(c)) }

func Complex64IsInt(c complex64) bool { return imag(c) == 0 && Float64IsInt(float64(real(c))) }

// Usually just the above statically typed functions would be all that is used, // but if it is desired to have a single function that can test any arbitrary // type, including the standard math/big types, user defined types based on // an integer, float, or complex builtin types, or user defined types that // have an IsInt() method, then reflection can be used.

type hasIsInt interface { IsInt() bool }

var bigIntT = reflect.TypeOf((*big.Int)(nil))

func IsInt(i interface{}) bool { if ci, ok := i.(hasIsInt); ok { // Handles things like *big.Rat return ci.IsInt() } switch v := reflect.ValueOf(i); v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: // Built-in types and any custom type based on them return true case reflect.Float32, reflect.Float64: // Built-in floats and anything based on them return Float64IsInt(v.Float()) case reflect.Complex64, reflect.Complex128: // Built-in complexes and anything based on them return Complex128IsInt(v.Complex()) case reflect.String: // Could also do strconv.ParseFloat then FloatIsInt but // big.Rat handles everything ParseFloat can plus more. // Note, there is no strconv.ParseComplex. if r, ok := new(big.Rat).SetString(v.String()); ok { return r.IsInt() } case reflect.Ptr: // Special case for math/big.Int if v.Type() == bigIntT { return true } } return false }

// The rest is just demonstration and display

type intbased int16 type complexbased complex64 type customIntegerType struct { // Anything that stores or represents a sub-set // of integer values in any way desired. }

func (customIntegerType) IsInt() bool { return true } func (customIntegerType) String() string { return "<…>" }

func main() { hdr := fmt.Sprintf("%27s  %-6s %s\n", "Input", "IsInt", "Type") show2 := func(t bool, i interface{}, args ...interface{}) { istr := fmt.Sprint(i) fmt.Printf("%27s  %-6t %T ", istr, t, i) fmt.Println(args...) } show := func(i interface{}, args ...interface{}) { show2(IsInt(i), i, args...) }

fmt.Print("Using Float64IsInt with float64:\n", hdr) neg1 := -1. for _, f := range []float64{ 0, neg1 * 0, -2, -2.000000000000001, 10. / 2, 22. / 3, math.Pi, math.MinInt64, math.MaxUint64, math.SmallestNonzeroFloat64, math.MaxFloat64, math.NaN(), math.Inf(1), math.Inf(-1), } { show2(Float64IsInt(f), f) }

fmt.Print("\nUsing Complex128IsInt with complex128:\n", hdr) for _, c := range []complex128{ 3, 1i, 0i, 3.4, } { show2(Complex128IsInt(c), c) }

fmt.Println("\nUsing reflection:") fmt.Print(hdr) show("hello") show(math.MaxFloat64) show("9e100") show("(4+0i)", "(complex strings not parsed)") show(4 + 0i) show(rune('§'), "or rune") show(byte('A'), "or byte") var t1 intbased = 5200 var t2a, t2b complexbased = 5 + 0i, 5 + 1i show(t1) show(t2a) show(t2b) x := uintptr(unsafe.Pointer(&t2b)) show(x) show(math.MinInt32) show(uint64(math.MaxUint64)) b, _ := new(big.Int).SetString(strings.Repeat("9", 25), 0) show(b) r := new(big.Rat) show(r) r.SetString("2/3") show(r) show(r.SetFrac(b, new(big.Int).SetInt64(9))) show("12345/5") show(new(customIntegerType)) }</lang>

Output:
Using Float64IsInt with float64:
                      Input  IsInt  Type
                          0  true   float64 
                         -0  true   float64 
                         -2  true   float64 
         -2.000000000000001  false  float64 
                          5  true   float64 
          7.333333333333333  false  float64 
          3.141592653589793  false  float64 
     -9.223372036854776e+18  true   float64 
     1.8446744073709552e+19  true   float64 
                     5e-324  false  float64 
    1.7976931348623157e+308  true   float64 
                        NaN  false  float64 
                       +Inf  false  float64 
                       -Inf  false  float64 

Using Complex128IsInt with complex128:
                      Input  IsInt  Type
                     (3+0i)  true   complex128 
                     (0+1i)  false  complex128 
                     (0+0i)  true   complex128 
                   (3.4+0i)  false  complex128 

Using reflection:
                      Input  IsInt  Type
                      hello  false  string 
    1.7976931348623157e+308  true   float64 
                      9e100  true   string 
                     (4+0i)  false  string (complex strings not parsed)
                     (4+0i)  true   complex128 
                        167  true   int32 or rune
                         65  true   uint8 or byte
                       5200  true   main.intbased 
                     (5+0i)  true   main.complexbased 
                     (5+1i)  false  main.complexbased 
               833358060808  true   uintptr 
                -2147483648  true   int 
       18446744073709551615  true   uint64 
  9999999999999999999999999  true   *big.Int 
                        0/1  true   *big.Rat 
                        2/3  false  *big.Rat 
1111111111111111111111111/1  true   *big.Rat 
                    12345/5  true   string 
                        <…>  true   *main.customIntegerType 

J

Solution:<lang j> isInt =: (= <.) *. (= {.@+.)</lang> Alternative solution (remainder after diving by 1?): <lang j> isInt=: (0 = 1&|) *. (0 = {:@+.)</lang> Example:<lang j> isInt 3.14 7 1.4j0 4j0 5j3 0 1 0 1 0</lang>

jq

Works with: jq version 1.4

jq does not have builtin support for complex numbers or rationals, but in conformity with the Rosetta Code page Arithmetic/Complex#jq, we shall assume in the following that the complex number x+iy has been identified with the array [x,y]. To illustrate how the task can be solved for rationals, we shall also identify the rational numbers p/q with JSON objects that have the form: {"type": "rational", "p": p, "q": q}. <lang jq>def is_integral:

 if type == "number" then . == floor
 elif type == "array" then
      length == 2 and .[1] == 0 and (.[0] | is_integral)
 else type == "object"
      and .type == "rational" 
      and  .q != 0
      and (.q | is_integral)
      and ((.p / .q) | is_integral)
 end ;</lang>

Example: <lang jq>(

  0,   -1, [3,0], {"p": 4, "q": 2, "type": "rational"},
1.1, -1.1, [3,1], {"p": 5, "q": 2, "type": "rational"}
) | "\(.) => \(if is_integral then "integral" else "" end)"</lang>
Output:

<lang sh>$ jq -r -n -f is_integral.jq 0 => integral -1 => integral [3,0] => integral {"p":4,"q":2,"type":"rational"} => integral 1.1 => -1.1 => [3,1] => {"p":5,"q":2,"type":"rational"} => </lang>

Lua

<lang lua> function IsInt(What) if tonumber(What) == What and math.floor(tonumber(What)) == tonumber(What) then return true end return false

   end</lang>
Output:
IsInt(5):true
IsInt(6):true
IsInt(-5):true
IsInt(123.4123):false
IsInt(123123123123123):true

ooRexx

<lang oorexx>/* REXX ---------------------------------------------------------------

  • 22.06.2014 Walter Pachl using a complex data class
  • ooRexx Distribution contains an elaborate complex class
  • parts of which are used here
  • --------------------------------------------------------------------*/

Numeric Digits 1000 Call test_integer .complex~new(1e+12,0e-3) Call test_integer .complex~new(3.14) Call test_integer .complex~new(1.00000) Call test_integer .complex~new(33) Call test_integer .complex~new(999999999) Call test_integer .complex~new(99999999999) Call test_integer .complex~new(1e272) Call test_integer .complex~new(0) Call test_integer .complex~new(1.000,-3) Call test_integer .complex~new(1.000,-3.3) Call test_integer .complex~new(,4) Call test_integer .complex~new(2.00000000,+0) Call test_integer .complex~new(,0) Call test_integer .complex~new(333) Call test_integer .complex~new(-1,-1) Call test_integer .complex~new(1,1) Call test_integer .complex~new(,.00) Call test_integer .complex~new(,1) Call test_integer .complex~new(0003,00.0) Exit

test_integer: Use Arg cpx cpxa=left(changestr('+-',cpx,'-'),13) -- beautify representation Select

 When cpx~imaginary<>0 Then
   Say cpxa 'is not an integer'
 When datatype(cpx~real,'W') Then
   Say cpxa 'is an integer'
 Otherwise
   Say cpxa 'is not an integer'
 End

Return

class complex
method init /* initialize a complex number */

expose real imaginary /* expose the state data */ use Strict arg first=0, second=0 /* access the two numbers */ real = first + 0 /* force rounding */ imaginary = second + 0 /* force rounding on the second */

method real /* return real part of a complex */

expose real /* access the state information */ return real /* return that value */

method imaginary /* return imaginary part */

expose imaginary /* access the state information */ return imaginary /* return the value */

method string /* format as a string value */

expose real imaginary /* get the state info */ return real'+'imaginary'i' /* format as real+imaginaryi */</lang> output

1E+12+0i      is an integer
3.14+0i       is not an integer
1.00000+0i    is an integer
33+0i         is an integer
999999999+0i  is an integer
1.00000000E+1 is an integer
1E+272+0i     is an integer
0+0i          is an integer
1.000-3i      is not an integer
1.000-3.3i    is not an integer
0+4i          is not an integer
2.00000000+0i is an integer
0+0i          is an integer
333+0i        is an integer
-1-1i         is not an integer
1+1i          is not an integer
0+0i          is an integer
0+1i          is not an integer
3+0i          is an integer


Mathematica / Wolfram Language

The built-in function IntegerQ performs the required test <lang Mathematica>IntegerQ /@ {E, 2.4, 7, 9/2}</lang>

Output:
{False,False,True,False}

PARI/GP

The operator == does what we want here, comparing a number mathematically regardless of how it's stored. === checks literal equivalence instead.

<lang parigp>isInteger(z)=real(z)==real(z)\1 && imag(z)==imag(z)\1; apply(isInteger, [7, I, 1.7 + I, 10.0 + I, 1.0 - 7.0 * I])</lang>

Output:
%1 = [1, 1, 0, 1, 1]

Perl

<lang perl6>use Math::Complex;

sub is_int {

   my $number = shift;
   
   if (ref $number eq 'Math::Complex') {
       return 0 if $number->Im != 0;
       $number = $number->Re;
   }
   
   return int($number) == $number;

}

for (5, 4.1, sqrt(2), sqrt(4), 1.1e10, 3.0-0.0*i, 4-3*i, 5.6+0*i) {

   printf "%20s is%s an integer\n", $_, (is_int($_) ? "" : " NOT");

}</lang>

Output:
                   5 is an integer
                 4.1 is NOT an integer
     1.4142135623731 is NOT an integer
                   2 is an integer
         11000000000 is an integer
                   3 is an integer
                4-3i is NOT an integer
                 5.6 is NOT an integer

Perl 6

In Perl 6, classes that implement the Numeric role have a method called narrow which returns an object with the same value but with the most appropriate type. So we can just test the type of that object.

<lang perl6>for pi, 1e5, 1+0i {

   say "$_ is{" NOT" if .narrow !~~ Int} an integer.";

}</lang>

Output:
3.14159265358979 is NOT an integer.
100000 is an integer.
1+0i is an integer.

PicoLisp

Pico Lisp scaled fixed-point numbers. Every number is stored an an Integer and a Non-integer only relative to the scale applied. For this example we assume that all numbers are generated with the same scale. This is the common case. <lang PicoLisp> (de int? (N)

 (= N (* 1.0 (/ N 1.0)))) #returns T or NIL

(de integer? (N)

 (and (= N (* 1.0 (/ N 1.0))) N)) #returns value of N or NIL

(scl 4) #-> 4 # *Scl the global which holds 1.0 #-> 10000 (int? 1.0) #-> T (int? 1) #-> NIL # 1 with a scale of 4 is same as 0.0001 which is not an Integer (int? -1.0) #-> T (int? -0.0) #-> T (int? "RE") #-> "RE" -- Number expected (int? (*/ 2.0 1.0 3.0)) #-> NIL # 6667 is not an integer of the scale of 4, use of */ because of the scale </lang>

Python

<lang python>>>> def isint(f):

   return complex(f).imag == 0 and complex(f).real.is_integer()

>>> [isint(f) for f in (1.0, 2, (3.0+0.0j), 4.1, (3+4j), (5.6+0j))] [True, True, True, False, False, False] >>> </lang>

Racket

The scheme/racket number pyramid is notoriously difficult to navigate. The following are integers representations that *I* know of, but I'm sure there are plenty more!

See documentation for integer?

<lang racket>#lang racket (require tests/eli-tester)

(test ;; known representations of integers:

;; - as exacts
(integer? -1) => #t
(integer?  0) => #t
(integer?  1) => #t
(integer?   1234879378539875943875937598379587539875498792424323432432343242423432432) => #t
(integer?  -1234879378539875943875937598379587539875498792424323432432343242423432432) => #t
(integer?  #xff) => #t

;; - as inexacts
(integer? -1.) => #t
(integer?  0.) => #t
(integer?  1.) => #t
(integer?  1234879378539875943875937598379587539875498792424323432432343242423432432.) => #t
(integer?  #xff.0) => #t
;; - but without a decimal fractional part
(integer? -1.1) => #f

;; - fractional representation
(integer? -42/3) => #t
(integer?   0/1) => #t
(integer?  27/9) => #t
(integer?  #xff/f) => #t
(integer?  #b11111111/1111) => #t
;; - but obviously not fractions
(integer? 5/7) => #f

; - as scientific
(integer?  1.23e2) => #t
(integer?  1.23e120) => #t
; - but not with a small exponent
(integer?  1.23e1) => #f

; - complex representations with 0 imaginary component
;   ℤ is a subset of the sets of rational and /real/ numbers and
(integer? 1+0i) => #t
(integer? (sqr 0+1i)) => #t
(integer? 0+1i) => #f

;; oh, there's so much else that isn't an integer:
(integer? "woo") => #f
(integer? "100") => #f
(integer? (string->number "22/11")) => #t ; just cast it!
(integer? +inf.0) => #f
(integer? -inf.0) => #f
(integer? +nan.0) => #f ; duh! it's not even a number!
(integer? -NaN.0) => #f
(integer? pi) => #f
)

</lang> All tests pass.

REXX

version 1

<lang rexx>/* REXX ---------------------------------------------------------------

  • 20.06.2014 Walter Pachl
  • 22.06.2014 WP add complex numbers such as 13-12j etc.
  • (using 13e-12 or so is not (yet) supported)
  • --------------------------------------------------------------------*/

Call test_integer 3.14 Call test_integer 1.00000 Call test_integer 33 Call test_integer 999999999 Call test_integer 99999999999 Call test_integer 1e272 Call test_integer 'AA' Call test_integer '0' Call test_integer '1.000-3i' Call test_integer '1.000-3.3i' Call test_integer '4j' Call test_integer '2.00000000+0j' Call test_integer '0j' Call test_integer '333' Call test_integer '-1-i' Call test_integer '1+i' Call test_integer '.00i' Call test_integer 'j' Call test_integer '0003-00.0j' Exit

test_integer: Parse Arg xx Numeric Digits 1000 Parse Value parse_number(xx) With x imag If imag<>0 Then Do

 Say left(xx,13) 'is not an integer (imaginary part is not zero)'
 Return
 End

Select

 When datatype(x)<>'NUM' Then
   Say left(xx,13) 'is not an integer (not even a number)'
 Otherwise Do
   If datatype(x,'W') Then
     Say left(xx,13) 'is an integer'
   Else
     Say left(xx,13) 'isnt an integer'
   End
 End

Return parse_number: Procedure

 Parse Upper Arg x
 x=translate(x,'I','J')
 If pos('I',x)>0 Then Do
   pi=verify(x,'+-','M')
   Select
     When pi>1 Then Do
       real=left(x,pi-1)
       imag=substr(x,pi)
       End
     When pi=0 Then Do
       real=0
       imag=x
       End
     Otherwise /*pi=1*/Do
       p2=verify(substr(x,2),'+-','M')
       If p2>0 Then Do
         real=left(x,p2)
         imag=substr(x,p2+1)
         End
       Else Do
         real=0
         imag=x
         End
       End
     End
   End
 Else Do
   real=x
   imag='0I'
   End
 pi=verify(imag,'+-','M')
 If pi=0 Then Do
   Parse Var imag imag_v 'I'
   imag_sign='+'
   End
 Else
   Parse Var imag imag_sign 2 imag_v 'I'
 If imag_v= Then
   imag_v=1
 imag=imag_sign||imag_v
 Return real imag</lang>

output

3.14          isn't an integer
1.00000       is an integer
33            is an integer
999999999     is an integer
99999999999   is an integer
1E272         is an integer
AA            is not an integer (not even a number)
0             is an integer
1.000-3i      is not an integer (imaginary part is not zero)
1.000-3.3i    is not an integer (imaginary part is not zero)
4j            is not an integer (imaginary part is not zero)
2.00000000+0j is an integer
0j            is an integer
333           is an integer
-1-i          is not an integer (imaginary part is not zero)
1+i           is not an integer (imaginary part is not zero)
.00i          is an integer
j             is not an integer (imaginary part is not zero)
0003-00.0j    is an integer

version 2

This REXX version handles an exponent indicator of E, D, or Q (either lower or uppercase), and it also supports a trailing I or J imaginary indicator.

This version also handles numbers   larger   than can be stored (within REXX) as simple integers within the limits of numeric digits.   Also, most REXXes have a limit on the minimum/maximum value of the power in exponentiated numbers. <lang rexx>/*REXX pgm tests if a # (possibly complex) is equivalent to an integer.*/ numeric digits 3000 /*be able to handle big integers.*/ parse arg #s /*get optional #s list from C.L. */ if #s= then #s= '3.14 1.00000 33 999999999 99999999999 1e272 AA 0' ,

                  '1.000-3i 1.000-3.3i 4j 2.00000000+0j 0j 333 -1-i'    ,
                  '1+i .00i j 0003-00.0j 1.2d1 2e55666 +0003-00.0j +0j' ,
                  '-.3q+2 -0i +03.0e+01+0.00e+20j -030.0e-001+0.0e-020j'
                                      /* [↑]  use these #s for defaults*/
 do j=1  for words(#s); ox=word(#s,j) /*obtain a word from the #s list.*/
 parse  upper  var ox x               /*get an uppercase version of OX.*/
 x=translate(x, 'EEI', "QDJ")         /*alt. exponent & imag indicator.*/
 if right(x,1)=='I'  then call tImag  /*has the X number an imag. part?*/
 if isInt(x)  then say  right(ox,55)  "     is an integer."     /*yup. */
              else say  right(ox,55)  "  isn't an integer."     /*nope.*/
 end   /*j*/                          /* [↑]  process each # in list.  */

exit /*stick a fork in it, we're done.*/ /*──────────────────────────────────ISINT subroutine────────────────────*/ isInt: procedure; parse arg n /*obtain the number in question. */ if datatype(n, 'Whole') then return 1 /*it's a simple integer (small). */ parse var n m 'E' p /*separate base from the 10's pow*/ if \datatype(p, 'Numb') then return 0 /*Not an integer if P not a int.*/ return p>0 | m=0 /*Is power>0 or mantissa = zero? */ /*──────────────────────────────────ISSIGN subroutine───────────────────*/ isSign: arg ? 2; return ?=='+' |?=='-' /*concise method to test a sign. */ /*──────────────────────────────────TIMAG subroutine────────────────────*/ tImag: x=left(x, length(x)-1) /*strip the trailing I or J. */ if isInt(x) then do /*is what's remaining an integer?*/

                  if x\=0  then x=.   /*what's remaining isn't = zero. */
                  return              /*return to invoker either way.  */
                  end                 /* [↑]  handle simple imag. case.*/

if isSign(x) then x=substr(x,2) /*strip leading sign from X ? */ e=verify(x, .0123456789) /*find 1st char not a digit | dot*/ if e==0 then do; x=.; return; end /*Nothing? Then it's ¬ an integer*/ y=substr(x, e, 1) /*Y is the suspect character. */ if isSign(y) then do /*is suspect char a plus | minus?*/

                  z=substr(x, e+1)    /*obtain the imaginary part of X.*/
                  x=  left(x, e-1)    /*   "    "    real      "   " " */
                  if isInt(z) then if z=0  then return    /*imag. is 0.*/
                  x=.                 /*imaginary part isn't zero.     */
                  end                 /* [↑]  end of imag. part of  X. */

if y=='E' then do /*the real part of X has a power.*/

               p=substr(x, e+1)       /*obtain power of real part of X.*/
               _=  left(p, 1)         /*obtain the possible sign of pow*/
               if isSign(_)  then p=substr(p, 2) /*strip the power sign*/
               s=verify(p, '-+', "M")            /*imaginary sep char. */
               if s==0 then do; x=.; return; end /*No sign? Not integer*/
               z=substr(p, s+1)                  /*get the imag. part. */
               x=  left(x, e+s)                  /* "   "  real    "   */
               if isInt(z) then if z\=0 then x=. /*Not imag=0?  Not int*/
               end                               /* [↑]  handle imag.  */

return /*return to invoker. */</lang> output using the default input:

                                                   3.14   isn't an integer.
                                                1.00000      is an integer.
                                                     33      is an integer.
                                              999999999      is an integer.
                                            99999999999      is an integer.
                                                  1e272      is an integer.
                                                     AA   isn't an integer.
                                                      0      is an integer.
                                               1.000-3i   isn't an integer.
                                             1.000-3.3i   isn't an integer.
                                                     4j   isn't an integer.
                                          2.00000000+0j      is an integer.
                                                     0j      is an integer.
                                                    333      is an integer.
                                                   -1-i   isn't an integer.
                                                    1+i   isn't an integer.
                                                   .00i      is an integer.
                                                      j   isn't an integer.
                                             0003-00.0j      is an integer.
                                                  1.2d1      is an integer.
                                                2e55666      is an integer.
                                            +0003-00.0j      is an integer.
                                                    +0j      is an integer.
                                                 -.3q+2      is an integer.
                                                    -0i      is an integer.
                                    +03.0e+01+0.00e+20j      is an integer.
                                  -030.0e-001+0.0e-020j      is an integer.

version 3

This REXX version is the same as the 2nd version, but it also supports multiple (abutted) unary operators.

I.E.:   ++30e-1   -   +0j

would be considered an integer   (extra blanks were added to show the number with more clarity). <lang rexx>/*REXX pgm tests if a # (possibly complex) is equivalent to an integer.*/ numeric digits 3000 /*be able to handle big integers.*/ unaB='++ -- -+ +-' /*list of unary operators. */ unaA='+ + - -' /*list of unary operators trans. */ parse arg #s /*get optional #s list from C.L. */ if #s= then #s= '245+-00.0e-12i 245++++++0e+12j --3450d-1----0.0d-1j' ,

                  '4.5e11111222223333344444555556666677777888889999900'
                                      /* [↑]  use these #s for defaults*/
 do j=1  for words(#s); ox=word(#s,j) /*obtain a word from the #s list.*/
 parse  upper  var ox x               /*get an uppercase version of OX.*/
 x=translate(x, 'EEJ', "QDI")         /*alt. exponent & imag indicator?*/
   do k=1  for words(unaB)            /*process every possible unary op*/
   _=word(unaB,k)                     /*unary operator to be changed.  */
     do  while  pos(_,x)\==0          /*keep changing 'til no more left*/
     x=changestr(_, x, word(unaA,k))  /*reduce all uniry operators.    */
     end   /*while*/
   end     /*k*/
 if right(x,1)=='J'  then call tImag  /*has the X number an imag. part?*/
 if isInt(x)  then say  right(ox,55)  "     is an integer."     /*yup. */
              else say  right(ox,55)  "  isn't an integer."     /*nope.*/
 end   /*j*/

exit /*stick a fork in it, we're done.*/ /*──────────────────────────────────ISINT subroutine────────────────────*/ isInt: procedure; parse arg n /*obtain the number in question. */ if datatype(n, 'Whole') then return 1 /*it's a simple integer (small). */ parse var n m 'E' p /*separate base from the 10's pow*/ if \datatype(p, 'Numb') then return 0 /*Not an integer if P not a int.*/ return p>0 | m=0 /*Is power>0 or mantissa = zero? */ /*──────────────────────────────────ISSIGN subroutine───────────────────*/ isSign: arg ? 2; return ?=='+' |?=='-' /*concise method to test a sign. */ /*──────────────────────────────────TIMAG subroutine────────────────────*/ tImag: x=left(x, length(x)-1) /*strip the trailing I or J. */ if isInt(x) then do /*is what's remaining an integer?*/

                  if x\=0  then x=.   /*what's remaining isn't = zero. */
                  return              /*return to invoker either way.  */
                  end                 /* [↑]  handle simple imag. case.*/

if isSign(x) then x=substr(x,2) /*strip leading sign from X ? */ e=verify(x, .0123456789) /*find 1st char not a digit | dot*/ if e==0 then do; x=.; return; end /*Nothing? Then it's ¬ an integer*/ y=substr(x, e, 1) /*Y is the suspect character. */ if isSign(y) then do /*is suspect char a plus | minus?*/

                  z=substr(x, e+1)    /*obtain the imaginary part of X.*/
                  x=  left(x, e-1)    /*   "    "    real      "   " " */
                  if isInt(z) then if z=0  then return    /*imag. is 0.*/
                  x=.                 /*imaginary part isn't zero.     */
                  end                 /* [↑]  end of imag. part of  X. */

if y=='E' then do /*the real part of X has a power.*/

               p=substr(x, e+1)       /*obtain power of real part of X.*/
               _=  left(p, 1)         /*obtain the possible sign of pow*/
               if isSign(_)  then p=substr(p, 2) /*strip the power sign*/
               s=verify(p, '-+', "M")            /*imaginary sep char. */
               if s==0 then do; x=.; return; end /*No sign? Not integer*/
               z=substr(p, s+1)                  /*get the imag. part. */
               x=  left(x, e+s)                  /* "   "  real    "   */
               if isInt(z) then if z\=0 then x=. /*Not imag=0?  Not int*/
               end                               /* [↑]  handle imag.  */

return /*return to invoker. */</lang> output using the default input:

                                         245+-00.0e-12i      is an integer.
                                        245++++++0e+12j   isn't an integer.
                                   --3450d-1----0.0d-1j      is an integer.
    4.5e11111222223333344444555556666677777888889999900      is an integer.

Ruby

Testing for integerness of floats, rationals and complex numbers: <lang ruby> class Numeric

 def integer?
   self == self.to_i rescue false
 end

end

  1. Demo

ar = [2.0, 2.5, # 2 floats

     2.to_r, 2.5.to_r,      # 2 rationals
     2.to_c, 2+0.5i]        # 2 complex numbers

ar.each{|num| puts "#{num} integer? #{num.integer?}" } </lang>

Output:
2.0 integer? true
2.5 integer? false
2/1 integer? true
5/2 integer? false
2+0i integer? true
2+0.5i integer? false

Tcl

The simplest way is to test whether the value is (numerically) equal to itself cast as an integer. entier() performs this cast without imposing any word-size limits (as int() or wide() would).

<lang tcl>proc isNumberIntegral {x} {

   expr {$x == entier($x)}

}

  1. test with various kinds of numbers:

foreach x {1e100 3.14 7 1.000000000000001 1000000000000000000000 -22.7 -123.000} {

   puts [format "%s: %s" $x [expr {[isNumberIntegral $x] ? "yes" : "no"}]]

}</lang>

Output:
1e100: yes
3.14: no
7: yes
1.000000000000001: no
1000000000000000000000: yes
-22.7: no
-123.000: yes

Note that 1.0000000000000001 will pass this integer test, because its difference from 1.0 is beyond the precision of an IEEE binary64 float. This discrepancy will be visible in other languages, but perhaps more obvious in Tcl as such a value's string representation will persist:

<lang Tcl>% set a 1.0000000000000001 1.0000000000000001 % expr $a 1.0 % IsNumberIntegral $a 1 % puts $a 1.0000000000000001</lang>

compare Python:

<lang Python>>>> a = 1.0000000000000001 >>> a 1.0 >>> 1.0 == 1.0000000000000001 True</lang>

.. this is a fairly benign illustration of why comparing floating point values with == is usually a bad idea.

zkl

No complex type. <lang zkl>T(1, 2.0,4.1,"nope",self).apply((1).isType)</lang>

Output:
L(True,False,False,False,False)

All is not golden as BigInts (lib GMP) don't consider themselves to be integers so the above test would fail. For that case: <lang zkl>fcn isInt(x){ try{x==x.toInt()}catch{False}} var BN=Import("zklBigNum");

T(1, 2.0,4.1,"nope",self,BN(5)).apply(isInt);</lang>
Output:
L(True,True,False,False,False,True)

Note that the first float is now considered to have an integer equivalent.