user
Mathematically,

* the integers **Z** are included in the rational numbers **Q**,
* which are included in the real numbers **R**,
* which can be generalized to the complex numbers **C**.

This means that each of those larger sets, and the data types used to represent them, include some integers.

Task[edit]

Given a rational, real, or complex number of any type, test whether it is mathematically an integer.

Your code should handle all numeric data types commonly used in your programming language.

Discuss any limitations of your code.

Definition

For the purposes of this task, integerness means that a number could theoretically be represented as an integer at no loss of precision *(given an infinitely wide integer type)*.  
In other words:

| Set | Common representation | C++ type | Considered an integer... |
| --- | --- | --- | --- |
| rational numbers **Q** | fraction | `std::ratio` | ...if its denominator is 1 (in reduced form) |
| real numbers **Z** *(approximated)* | fixed-point |  | ...if it has no non-zero digits after the decimal point |
| floating-point | `float`, `double` | ...if the number of significant decimal places of its mantissa isn't greater than its exponent |
| complex numbers **C** | pair of real numbers | `std::complex` | ...if its real part is considered an integer and its imaginary part is zero |

Extra credit

Optionally, make your code accept a `tolerance` parameter for fuzzy testing. The tolerance is the maximum amount by which the number may differ from the nearest integer, to still be considered an integer.

This is useful in practice, because when dealing with approximate numeric types (such as floating point), there may already be round-off errors from previous calculations. For example, a float value of `0.9999999998` might actually be intended to represent the integer `1`.

Test cases

| Input | | Output | | Comment |
| --- | --- | --- | --- | --- |
| Type | Value | exact | tolerance = 0.00001 |
| decimal | `25.000000` | true | |  |
| `24.999999` | false | true |  |
| `25.000100` | false | |  |
| floating-point | `-2.1e120` | true | | This one is tricky, because in most languages it is too large to fit into a native integer type. It is, nonetheless, mathematically an integer, and your code should identify it as such. |
| `-5e-2` | false | |  |
| `NaN` | false | |  |
| `Inf` | false | | This one is debatable. If your code considers it an integer, that's okay too. |
| complex | `5.0+0.0i` | true | |  |
| `5-5i` | false | |  |

(The types and notations shown in these tables are merely examples – you should use the native data types and number literals of your programming language and standard library. Use a different set of test-cases, if this one doesn't demonstrate all relevant behavior.)

---
assistant
(formerly Perl 6)

In Raku, all numeric types have a method called narrow, which returns an object with the same value but of the most appropriate type. So we can just check if *that* object is an Int. This works even with floats with large exponents, because the Int type supports arbitrarily large integers.

For the extra credit task, we can add another multi candidate that checks the distance between the number and it's nearest integer, but then we'll have to handle complex numbers specially.

```
multi is-int ($n) { $n.narrow ~~ Int }

multi is-int ($n, :$tolerance!) {
    abs($n.round - $n) <= $tolerance
}

multi is-int (Complex $n, :$tolerance!) {
    is-int($n.re, :$tolerance) && abs($n.im) < $tolerance
}

# Testing:

for 25.000000, 24.999999, 25.000100, -2.1e120, -5e-2, Inf, NaN, 5.0+0.0i, 5-5i {
    printf "%-7s  %-9s  %-5s  %-5s\n", .^name, $_,
        is-int($_),
        is-int($_, :tolerance<0.00001>);
}

```

Output:

```
Rat      25         True   True 
Rat      24.999999  False  True 
Rat      25.0001    False  False
Num      -2.1e+120  True   True 
Num      -0.05      False  False
Num      Inf        False  False
Num      NaN        False  False
Complex  5+0i       True   True 
Complex  5-5i       False  False

```