# RFC: Add "is_representable_as_float()" and "is_representable_as_int()" functions

- Status: Withdrawn
- Authors: Alexandre Daubois, alexandredaubois@php.net
- Date: 2025-07-29
- Version: 1.0
- Implementation: https://github.com/php/php-src/pull/19308
- Original: https://wiki.php.net/rfc/is-representable-as-float-int
- Page: https://externals.io/rfc/is-representable-as-float-int
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Votes

### Implement (closed)

Yes: 0 · No: 0 · Abstain: 0

## Discussions on the mailing list

- [\[RFC\] Add "is_representable_as_float()" and "is_representable_as_int()" functions](https://externals.io/message/128296.md) — started on 2025-07-29, 28 messages

---

## Introduction

This RFC proposes the addition of two new functions to PHP's standard library: `is_representable_as_float()` and `is_representable_as_int()`.

These functions provide developers with a standardized way to check whether values can be losslessly converted between integer and floating-point representations. Among other things, this is particularly useful for:

- Ensuring data integrity when performing arithmetic operations ;
- Parsing input data of unknown type ;
- Validating data before storage or transmission.

Here is an example of a real use case: when serializing data, it is currently challenging to determine whether a numeric value can be safely represented as a float or an integer without loss of precision:

```php
<?php
 
// 9007199254740993 is NOT representable as a float
 
// currently, we can use is_numeric() to check if a value is numeric
// but this does not guarantee that the value can be represented as a float or an int
$data = ['price' => 9007199254740993];
if (/* how do I make sure the price can be represented in JSON? */) {
    // handle error, e.g., log it or throw an exception
    // or cast to string
}
 
// with this RFC
$data = ['price' => 9007199254740993];
if (!is_representable_as_float($data['price'])) {
    $data['price'] = (string) $data['price'];
}
?>
```

## Proposal

Add the following two functions:

- `function is_representable_as_float(mixed $value): bool`
- `function is_representable_as_int(mixed $value): bool`

**When does is\_representable\_as\_float() return true?**

- The value is a float
- The value is an integer that can be converted to a float without loss of precision
- The value is a string that represents a valid floating-point number (e.g., “3.14”, “1e10”, “-0.001”)
- The value is a string that represents a valid integer (e.g., “42”, “-7”) and can be converted to a float without loss of precision

About the loss of precision: it is important to know that IEEE 754 floating-point numbers can represent integers exactly up to 2^53 - 1 (inclusive) because the mantissa has 52 bits of precision plus an implicit leading bit. Therefore, any integer within this range can be represented as a float without loss of precision. An integer outside this range could lose precision when converted to a float. This is called the “safe integer range” for floats. MDN provides a good overview of this topic\[1\].

IEEE 754 floating-point numbers can represent all consecutive integers exactly up to 2^53 - 1 (inclusive). Beyond this range, only specific integers can be represented exactly, following a pattern based on the available mantissa bits:

- From 2^53 to 2^54: only even numbers (multiples of 2) ;
- From 2^54 to 2^55: only multiples of 4 ;
- From 2^55 to 2^56: only multiples of 8 ;
- And so on...

Additionally, pure powers of 2 (2^0, 2^1, 2^2, ..., up to 2^1023) can always be represented exactly because they require only a single bit in the mantissa.

The function returns true for any value that can be exactly represented as a float, including these special cases.

```php
<?php
 
is_representable_as_float(2**53);     // true
is_representable_as_float(2**53 + 1); // false, precision loss when cast to float
is_representable_as_float(42);        // true
is_representable_as_float("123.456"); // true
is_representable_as_float("1e308");   // false, not exactly representable as float
is_representable_as_float("1e400");   // false
 
// beyond safe range
is_representable_as_float(2**54);     // true (exact power of 2)
is_representable_as_float(2**54 + 2); // true (multiple of 2 in this range)
is_representable_as_float(2**54 + 1); // false (odd number, not representable)
 
// large pure powers of 2
is_representable_as_float(2**200);    // true (exact power of 2)
is_representable_as_float(2**1023);   // true (largest normal float)
is_representable_as_float(2**1024);   // true (overflow to infinity)
 
?>
```

**When does is\_representable\_as\_int() return true?**

- The value is an integer ;
- The value is a float not greater than PHP\_INT\_MAX and not less than PHP\_INT\_MIN, without fractional part ;
- The value is a string that represents a valid integer (e.g., “42”, “-7”) and can be converted to an integer within the range of PHP\_INT\_MIN and PHP\_INT\_MAX.

The function behavior depends on the platform's integer range:

```php
is_representable_as_int(2.0**31);      // true on 64-bit, false on 32-bit platforms
is_representable_as_int('2147483648'); // true on 64-bit, false on 32-bit platforms
```

More examples of the function return values:

```php
is_representable_as_int(42);         // true
is_representable_as_int(3.14);       // false, has a fractional part
is_representable_as_int("123");      // true
is_representable_as_int("123.456");  // false, has a fractional part
is_representable_as_int("1e10");     // true on 64-bit platforms, false on 32-bit platforms
is_representable_as_int("1e400");    // false, not exactly representable as int
```

### Naming

It's still unsure if the current naming of functions are a prefect fit. Here are a few other propositions to name the new functions:

- `is_safe_float()` / `is_safe_int()`
- `fits_float()` / `fits_int()`
- `can_cast_to_float()` / `can_cast_to_int()`

## Examples

```php
<?php
 
// validate before serialization
$data = ['price' => 9007199254740993];
if (!is_representable_as_float($data['price'])) {
    // handle error, e.g., log it or throw an exception
    // or cast to string!
    $data['price'] = (string) $data['price'];
}
 
// validate data from external API
function validateNumericInput($value) {
    if (is_numeric($value) && is_representable_as_int($value)) {
        return (int) $value;
    }
 
    // ...
}
 
// edge cases
is_representable_as_float(INF);        // true
is_representable_as_float(-INF);       // true
is_representable_as_float(NAN);        // true
is_representable_as_float("");         // false
is_representable_as_float(null);       // false
is_representable_as_float(false);      // false
is_representable_as_float(true);       // false
is_representable_as_float("  42  ");   // true, like "is_numeric()"
is_representable_as_float("\r42\n");   // true, like "is_numeric()"
is_representable_as_float("0x2A");     // false, like "is_numeric()"
is_representable_as_float("0b01110");  // false, like "is_numeric()"
is_representable_as_int(2.0);          // true
is_representable_as_int(-0.0);         // true
 
class MyClass {
    public function __toString() {
        return "42";
    }
}
 
is_representable_as_int(new MyClass()); // true because of __toString()
is_representable_as_float(new MyClass()); // true as well
 
?>
```

Note: these functions use locale-independent parsing, similar to `is_numeric()`. Decimal separator is always “.” regardless of locale settings.

## Backward Incompatible Changes

Existing code that declares a function with the same name will result in an error. However, this is unlikely to happen. A quick search on GitHub with the function names shows no results.

## Proposed PHP Version(s)

Next minor version, likely PHP 8.6

## Voting Choices

**Vote: Implement** — Yes: 0 · No: 0 · Abstain: 0 (closed)

## Patches and Tests

The pull request is available here: <https://github.com/php/php-src/pull/19308>

## References

\[1\] [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Number#number\_encoding](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding)
