Test integerness

From Rosetta Code
Revision as of 15:50, 2 July 2014 by Grondilu (talk | contribs) (→‎{{header|Perl 6}}: some explanations)
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.


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>

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


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.

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>

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.

Tcl

This example is incomplete. Please ensure that it meets all task requirements and remove this message.

The simplest method of doing this is testing whether the value is equal to the value after casting it to a integral value. <lang tcl>proc isNumberIntegral {x} {

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

} foreach x {3.14 7 1000000000000000000000} {

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

}</lang>

Output:
3.14: no
7: yes
1000000000000000000000: yes